mem-hotplug: avoid multiple zones sharing same boot strapping boot_pageset
[safe/jmp/linux-2.6] / kernel / power / snapshot.c
index 2b1a7bc..25ce010 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/console.h>
 #include <linux/highmem.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -233,7 +234,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
 
 #define BM_END_OF_MAP  (~0UL)
 
-#define BM_BITS_PER_BLOCK      (PAGE_SIZE << 3)
+#define BM_BITS_PER_BLOCK      (PAGE_SIZE * BITS_PER_BYTE)
 
 struct bm_block {
        struct list_head hook;  /* hook into a list of bitmap blocks */
@@ -275,7 +276,7 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free);
 
 /**
  *     create_bm_block_list - create a list of block bitmap objects
- *     @nr_blocks - number of blocks to allocate
+ *     @pages - number of pages to track
  *     @list - list to put the allocated blocks into
  *     @ca - chain allocator to be used for allocating memory
  */
@@ -619,7 +620,7 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
                BUG_ON(!region);
        } else
                /* This allocation cannot fail */
-               region = alloc_bootmem_low(sizeof(struct nosave_region));
+               region = alloc_bootmem(sizeof(struct nosave_region));
        region->start_pfn = start_pfn;
        region->end_pfn = end_pfn;
        list_add_tail(&region->list, &nosave_regions);
@@ -853,7 +854,7 @@ static unsigned int count_highmem_pages(void)
        struct zone *zone;
        unsigned int n = 0;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                unsigned long pfn, max_zone_pfn;
 
                if (!is_highmem(zone))
@@ -916,7 +917,7 @@ static unsigned int count_data_pages(void)
        unsigned long pfn, max_zone_pfn;
        unsigned int n = 0;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                if (is_highmem(zone))
                        continue;
 
@@ -1010,7 +1011,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
        struct zone *zone;
        unsigned long pfn;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                unsigned long max_zone_pfn;
 
                mark_free_pages(zone);
@@ -1065,7 +1066,7 @@ void swsusp_free(void)
        struct zone *zone;
        unsigned long pfn, max_zone_pfn;
 
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
                for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
                        if (pfn_valid(pfn)) {
@@ -1181,7 +1182,7 @@ static void free_unnecessary_pages(void)
 
        memory_bm_position_reset(&copy_bm);
 
-       while (to_free_normal > 0 && to_free_highmem > 0) {
+       while (to_free_normal > 0 || to_free_highmem > 0) {
                unsigned long pfn = memory_bm_next_pfn(&copy_bm);
                struct page *page = pfn_to_page(pfn);
 
@@ -1204,6 +1205,36 @@ static void free_unnecessary_pages(void)
 }
 
 /**
+ * minimum_image_size - Estimate the minimum acceptable size of an image
+ * @saveable: Number of saveable pages in the system.
+ *
+ * We want to avoid attempting to free too much memory too hard, so estimate the
+ * minimum acceptable size of a hibernation image to use as the lower limit for
+ * preallocating memory.
+ *
+ * We assume that the minimum image size should be proportional to
+ *
+ * [number of saveable pages] - [number of pages that can be freed in theory]
+ *
+ * where the second term is the sum of (1) reclaimable slab pages, (2) active
+ * and (3) inactive anonymouns pages, (4) active and (5) inactive file pages,
+ * minus mapped file pages.
+ */
+static unsigned long minimum_image_size(unsigned long saveable)
+{
+       unsigned long size;
+
+       size = global_page_state(NR_SLAB_RECLAIMABLE)
+               + global_page_state(NR_ACTIVE_ANON)
+               + global_page_state(NR_INACTIVE_ANON)
+               + global_page_state(NR_ACTIVE_FILE)
+               + global_page_state(NR_INACTIVE_FILE)
+               - global_page_state(NR_FILE_MAPPED);
+
+       return saveable <= size ? 0 : saveable - size;
+}
+
+/**
  * hibernate_preallocate_memory - Preallocate memory for hibernation image
  *
  * To create a hibernation image it is necessary to make a copy of every page
@@ -1220,8 +1251,8 @@ static void free_unnecessary_pages(void)
  *
  * If image_size is set below the number following from the above formula,
  * the preallocation of memory is continued until the total number of saveable
- * pages in the system is below the requested image size or it is impossible to
- * allocate more memory, whichever happens first.
+ * pages in the system is below the requested image size or the minimum
+ * acceptable image size returned by minimum_image_size(), whichever is greater.
  */
 int hibernate_preallocate_memory(void)
 {
@@ -1282,6 +1313,11 @@ int hibernate_preallocate_memory(void)
                goto out;
        }
 
+       /* Estimate the minimum size of the image. */
+       pages = minimum_image_size(saveable);
+       if (size < pages)
+               size = min_t(unsigned long, pages, max_size);
+
        /*
         * Let the memory management subsystem know that we're going to need a
         * large number of page frames to allocate and make it free some memory.
@@ -1294,8 +1330,8 @@ int hibernate_preallocate_memory(void)
         * The number of saveable pages in memory was too high, so apply some
         * pressure to decrease it.  First, make room for the largest possible
         * image and fail if that doesn't work.  Next, try to decrease the size
-        * of the image as much as indicated by image_size using allocations
-        * from highmem and non-highmem zones separately.
+        * of the image as much as indicated by 'size' using allocations from
+        * highmem and non-highmem zones separately.
         */
        pages_highmem = preallocate_image_highmem(highmem / 2);
        alloc = (count - max_size) - pages_highmem;
@@ -1362,7 +1398,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
        struct zone *zone;
        unsigned int free = alloc_normal;
 
-       for_each_zone(zone)
+       for_each_populated_zone(zone)
                if (!is_highmem(zone))
                        free += zone_page_state(zone, NR_FREE_PAGES);
 
@@ -1465,7 +1501,7 @@ asmlinkage int swsusp_save(void)
 {
        unsigned int nr_pages, nr_highmem;
 
-       printk(KERN_INFO "PM: Creating hibernation image: \n");
+       printk(KERN_INFO "PM: Creating hibernation image:\n");
 
        drain_local_pages(NULL);
        nr_pages = count_data_pages();
@@ -1568,14 +1604,9 @@ pack_pfns(unsigned long *buf, struct memory_bitmap *bm)
  *     snapshot_handle structure.  The structure gets updated and a pointer
  *     to it should be passed to this function every next time.
  *
- *     The @count parameter should contain the number of bytes the caller
- *     wants to read from the snapshot.  It must not be zero.
- *
  *     On success the function returns a positive number.  Then, the caller
  *     is allowed to read up to the returned number of bytes from the memory
- *     location computed by the data_of() macro.  The number returned
- *     may be smaller than @count, but this only happens if the read would
- *     cross a page boundary otherwise.
+ *     location computed by the data_of() macro.
  *
  *     The function returns 0 to indicate the end of data stream condition,
  *     and a negative number is returned on error.  In such cases the
@@ -1583,7 +1614,7 @@ pack_pfns(unsigned long *buf, struct memory_bitmap *bm)
  *     any more.
  */
 
-int snapshot_read_next(struct snapshot_handle *handle, size_t count)
+int snapshot_read_next(struct snapshot_handle *handle)
 {
        if (handle->cur > nr_meta_pages + nr_copy_pages)
                return 0;
@@ -1594,7 +1625,7 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count)
                if (!buffer)
                        return -ENOMEM;
        }
-       if (!handle->offset) {
+       if (!handle->cur) {
                int error;
 
                error = init_header((struct swsusp_info *)buffer);
@@ -1603,42 +1634,30 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count)
                handle->buffer = buffer;
                memory_bm_position_reset(&orig_bm);
                memory_bm_position_reset(&copy_bm);
-       }
-       if (handle->prev < handle->cur) {
-               if (handle->cur <= nr_meta_pages) {
-                       memset(buffer, 0, PAGE_SIZE);
-                       pack_pfns(buffer, &orig_bm);
-               } else {
-                       struct page *page;
+       } else if (handle->cur <= nr_meta_pages) {
+               memset(buffer, 0, PAGE_SIZE);
+               pack_pfns(buffer, &orig_bm);
+       } else {
+               struct page *page;
 
-                       page = pfn_to_page(memory_bm_next_pfn(&copy_bm));
-                       if (PageHighMem(page)) {
-                               /* Highmem pages are copied to the buffer,
-                                * because we can't return with a kmapped
-                                * highmem page (we may not be called again).
-                                */
-                               void *kaddr;
+               page = pfn_to_page(memory_bm_next_pfn(&copy_bm));
+               if (PageHighMem(page)) {
+                       /* Highmem pages are copied to the buffer,
+                        * because we can't return with a kmapped
+                        * highmem page (we may not be called again).
+                        */
+                       void *kaddr;
 
-                               kaddr = kmap_atomic(page, KM_USER0);
-                               memcpy(buffer, kaddr, PAGE_SIZE);
-                               kunmap_atomic(kaddr, KM_USER0);
-                               handle->buffer = buffer;
-                       } else {
-                               handle->buffer = page_address(page);
-                       }
+                       kaddr = kmap_atomic(page, KM_USER0);
+                       memcpy(buffer, kaddr, PAGE_SIZE);
+                       kunmap_atomic(kaddr, KM_USER0);
+                       handle->buffer = buffer;
+               } else {
+                       handle->buffer = page_address(page);
                }
-               handle->prev = handle->cur;
        }
-       handle->buf_offset = handle->cur_offset;
-       if (handle->cur_offset + count >= PAGE_SIZE) {
-               count = PAGE_SIZE - handle->cur_offset;
-               handle->cur_offset = 0;
-               handle->cur++;
-       } else {
-               handle->cur_offset += count;
-       }
-       handle->offset += count;
-       return count;
+       handle->cur++;
+       return PAGE_SIZE;
 }
 
 /**
@@ -1653,7 +1672,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm)
        unsigned long pfn, max_zone_pfn;
 
        /* Clear page flags */
-       for_each_zone(zone) {
+       for_each_populated_zone(zone) {
                max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
                for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
                        if (pfn_valid(pfn))
@@ -2097,14 +2116,9 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
  *     snapshot_handle structure.  The structure gets updated and a pointer
  *     to it should be passed to this function every next time.
  *
- *     The @count parameter should contain the number of bytes the caller
- *     wants to write to the image.  It must not be zero.
- *
  *     On success the function returns a positive number.  Then, the caller
  *     is allowed to write up to the returned number of bytes to the memory
- *     location computed by the data_of() macro.  The number returned
- *     may be smaller than @count, but this only happens if the write would
- *     cross a page boundary otherwise.
+ *     location computed by the data_of() macro.
  *
  *     The function returns 0 to indicate the "end of file" condition,
  *     and a negative number is returned on error.  In such cases the
@@ -2112,16 +2126,18 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
  *     any more.
  */
 
-int snapshot_write_next(struct snapshot_handle *handle, size_t count)
+int snapshot_write_next(struct snapshot_handle *handle)
 {
        static struct chain_allocator ca;
        int error = 0;
 
        /* Check if we have already loaded the entire image */
-       if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages)
+       if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages)
                return 0;
 
-       if (handle->offset == 0) {
+       handle->sync_read = 1;
+
+       if (!handle->cur) {
                if (!buffer)
                        /* This makes the buffer be freed by swsusp_free() */
                        buffer = get_image_page(GFP_ATOMIC, PG_ANY);
@@ -2130,56 +2146,43 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count)
                        return -ENOMEM;
 
                handle->buffer = buffer;
-       }
-       handle->sync_read = 1;
-       if (handle->prev < handle->cur) {
-               if (handle->prev == 0) {
-                       error = load_header(buffer);
-                       if (error)
-                               return error;
+       } else if (handle->cur == 1) {
+               error = load_header(buffer);
+               if (error)
+                       return error;
 
-                       error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);
-                       if (error)
-                               return error;
+               error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);
+               if (error)
+                       return error;
 
-               } else if (handle->prev <= nr_meta_pages) {
-                       error = unpack_orig_pfns(buffer, &copy_bm);
+       } else if (handle->cur <= nr_meta_pages + 1) {
+               error = unpack_orig_pfns(buffer, &copy_bm);
+               if (error)
+                       return error;
+
+               if (handle->cur == nr_meta_pages + 1) {
+                       error = prepare_image(&orig_bm, &copy_bm);
                        if (error)
                                return error;
 
-                       if (handle->prev == nr_meta_pages) {
-                               error = prepare_image(&orig_bm, &copy_bm);
-                               if (error)
-                                       return error;
-
-                               chain_init(&ca, GFP_ATOMIC, PG_SAFE);
-                               memory_bm_position_reset(&orig_bm);
-                               restore_pblist = NULL;
-                               handle->buffer = get_buffer(&orig_bm, &ca);
-                               handle->sync_read = 0;
-                               if (IS_ERR(handle->buffer))
-                                       return PTR_ERR(handle->buffer);
-                       }
-               } else {
-                       copy_last_highmem_page();
+                       chain_init(&ca, GFP_ATOMIC, PG_SAFE);
+                       memory_bm_position_reset(&orig_bm);
+                       restore_pblist = NULL;
                        handle->buffer = get_buffer(&orig_bm, &ca);
+                       handle->sync_read = 0;
                        if (IS_ERR(handle->buffer))
                                return PTR_ERR(handle->buffer);
-                       if (handle->buffer != buffer)
-                               handle->sync_read = 0;
                }
-               handle->prev = handle->cur;
-       }
-       handle->buf_offset = handle->cur_offset;
-       if (handle->cur_offset + count >= PAGE_SIZE) {
-               count = PAGE_SIZE - handle->cur_offset;
-               handle->cur_offset = 0;
-               handle->cur++;
        } else {
-               handle->cur_offset += count;
+               copy_last_highmem_page();
+               handle->buffer = get_buffer(&orig_bm, &ca);
+               if (IS_ERR(handle->buffer))
+                       return PTR_ERR(handle->buffer);
+               if (handle->buffer != buffer)
+                       handle->sync_read = 0;
        }
-       handle->offset += count;
-       return count;
+       handle->cur++;
+       return PAGE_SIZE;
 }
 
 /**
@@ -2194,7 +2197,7 @@ void snapshot_write_finalize(struct snapshot_handle *handle)
 {
        copy_last_highmem_page();
        /* Free only if we have loaded the image entirely */
-       if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) {
+       if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages) {
                memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR);
                free_highmem_data();
        }