]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.fixes/Hibernate-Take-overlapping-zones-into-account-rev-2.patch
Imported linux-2.6.27.39 suse/xen patches.
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.fixes / Hibernate-Take-overlapping-zones-into-account-rev-2.patch
diff --git a/src/patches/suse-2.6.27.31/patches.fixes/Hibernate-Take-overlapping-zones-into-account-rev-2.patch b/src/patches/suse-2.6.27.31/patches.fixes/Hibernate-Take-overlapping-zones-into-account-rev-2.patch
deleted file mode 100644 (file)
index 2eff84f..0000000
+++ /dev/null
@@ -1,547 +0,0 @@
-From: Rafael J. Wysocki <rjw@suse.de>
-Subject: Hibernate: Take overlapping zones into account (rev. 2)
-References: bnc#438914
-Patch-mainline: 846705deb059c352cc0e5806d5964f815b8c6d98
-
-It has been requested to make hibernation work with memory
-hotplugging enabled and for this purpose the hibernation code has to
-be reworked to take the possible overlapping of zones into account.
-Thus, rework the hibernation memory bitmaps code to prevent
-duplication of PFNs from occuring and add checks to make sure that
-one page frame will not be marked as saveable many times.
-
-Additionally, use list.h lists instead of open-coded lists to
-implement the memory bitmaps.
-
-Signed-off-by: Rafael J. Wysocki <rjw@suse.de>
----
- kernel/power/snapshot.c |  327 ++++++++++++++++++++++++------------------------
- 1 file changed, 167 insertions(+), 160 deletions(-)
-
-Index: linux-2.6.27/kernel/power/snapshot.c
-===================================================================
---- linux-2.6.27.orig/kernel/power/snapshot.c
-+++ linux-2.6.27/kernel/power/snapshot.c
-@@ -25,6 +25,7 @@
- #include <linux/syscalls.h>
- #include <linux/console.h>
- #include <linux/highmem.h>
-+#include <linux/list.h>
- #include <asm/uaccess.h>
- #include <asm/mmu_context.h>
-@@ -192,12 +193,6 @@ static void *chain_alloc(struct chain_al
-       return ret;
- }
--static void chain_free(struct chain_allocator *ca, int clear_page_nosave)
--{
--      free_list_of_pages(ca->chain, clear_page_nosave);
--      memset(ca, 0, sizeof(struct chain_allocator));
--}
--
- /**
-  *    Data types related to memory bitmaps.
-  *
-@@ -233,7 +228,7 @@ static void chain_free(struct chain_allo
- #define BM_BITS_PER_BLOCK     (PAGE_SIZE << 3)
- struct bm_block {
--      struct bm_block *next;          /* next element of the list */
-+      struct list_head hook;  /* hook into a list of bitmap blocks */
-       unsigned long start_pfn;        /* pfn represented by the first bit */
-       unsigned long end_pfn;  /* pfn represented by the last bit plus 1 */
-       unsigned long *data;    /* bitmap representing pages */
-@@ -244,24 +239,15 @@ static inline unsigned long bm_block_bit
-       return bb->end_pfn - bb->start_pfn;
- }
--struct zone_bitmap {
--      struct zone_bitmap *next;       /* next element of the list */
--      unsigned long start_pfn;        /* minimal pfn in this zone */
--      unsigned long end_pfn;          /* maximal pfn in this zone plus 1 */
--      struct bm_block *bm_blocks;     /* list of bitmap blocks */
--      struct bm_block *cur_block;     /* recently used bitmap block */
--};
--
- /* strcut bm_position is used for browsing memory bitmaps */
- struct bm_position {
--      struct zone_bitmap *zone_bm;
-       struct bm_block *block;
-       int bit;
- };
- struct memory_bitmap {
--      struct zone_bitmap *zone_bm_list;       /* list of zone bitmaps */
-+      struct list_head blocks;        /* list of bitmap blocks */
-       struct linked_page *p_list;     /* list of pages used to store zone
-                                        * bitmap objects and bitmap block
-                                        * objects
-@@ -273,11 +259,7 @@ struct memory_bitmap {
- static void memory_bm_position_reset(struct memory_bitmap *bm)
- {
--      struct zone_bitmap *zone_bm;
--
--      zone_bm = bm->zone_bm_list;
--      bm->cur.zone_bm = zone_bm;
--      bm->cur.block = zone_bm->bm_blocks;
-+      bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook);
-       bm->cur.bit = 0;
- }
-@@ -285,151 +267,184 @@ static void memory_bm_free(struct memory
- /**
-  *    create_bm_block_list - create a list of block bitmap objects
-- */
--
--static inline struct bm_block *
--create_bm_block_list(unsigned int nr_blocks, struct chain_allocator *ca)
-+ *    @nr_blocks - number of blocks to allocate
-+ *    @list - list to put the allocated blocks into
-+ *    @ca - chain allocator to be used for allocating memory
-+ */
-+static int create_bm_block_list(unsigned long pages,
-+                              struct list_head *list,
-+                              struct chain_allocator *ca)
- {
--      struct bm_block *bblist = NULL;
-+      unsigned int nr_blocks = DIV_ROUND_UP(pages, BM_BITS_PER_BLOCK);
-       while (nr_blocks-- > 0) {
-               struct bm_block *bb;
-               bb = chain_alloc(ca, sizeof(struct bm_block));
-               if (!bb)
--                      return NULL;
--
--              bb->next = bblist;
--              bblist = bb;
-+                      return -ENOMEM;
-+              list_add(&bb->hook, list);
-       }
--      return bblist;
-+
-+      return 0;
- }
-+struct mem_extent {
-+      struct list_head hook;
-+      unsigned long start;
-+      unsigned long end;
-+};
-+
- /**
-- *    create_zone_bm_list - create a list of zone bitmap objects
-+ *    free_mem_extents - free a list of memory extents
-+ *    @list - list of extents to empty
-  */
-+static void free_mem_extents(struct list_head *list)
-+{
-+      struct mem_extent *ext, *aux;
--static inline struct zone_bitmap *
--create_zone_bm_list(unsigned int nr_zones, struct chain_allocator *ca)
-+      list_for_each_entry_safe(ext, aux, list, hook) {
-+              list_del(&ext->hook);
-+              kfree(ext);
-+      }
-+}
-+
-+/**
-+ *    create_mem_extents - create a list of memory extents representing
-+ *                         contiguous ranges of PFNs
-+ *    @list - list to put the extents into
-+ *    @gfp_mask - mask to use for memory allocations
-+ */
-+static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
- {
--      struct zone_bitmap *zbmlist = NULL;
-+      struct zone *zone;
--      while (nr_zones-- > 0) {
--              struct zone_bitmap *zbm;
-+      INIT_LIST_HEAD(list);
--              zbm = chain_alloc(ca, sizeof(struct zone_bitmap));
--              if (!zbm)
--                      return NULL;
-+      for_each_zone(zone) {
-+              unsigned long zone_start, zone_end;
-+              struct mem_extent *ext, *cur, *aux;
-+
-+              if (!populated_zone(zone))
-+                      continue;
-+
-+              zone_start = zone->zone_start_pfn;
-+              zone_end = zone->zone_start_pfn + zone->spanned_pages;
-+
-+              list_for_each_entry(ext, list, hook)
-+                      if (zone_start <= ext->end)
-+                              break;
-+
-+              if (&ext->hook == list || zone_end < ext->start) {
-+                      /* New extent is necessary */
-+                      struct mem_extent *new_ext;
-+
-+                      new_ext = kzalloc(sizeof(struct mem_extent), gfp_mask);
-+                      if (!new_ext) {
-+                              free_mem_extents(list);
-+                              return -ENOMEM;
-+                      }
-+                      new_ext->start = zone_start;
-+                      new_ext->end = zone_end;
-+                      list_add_tail(&new_ext->hook, &ext->hook);
-+                      continue;
-+              }
--              zbm->next = zbmlist;
--              zbmlist = zbm;
-+              /* Merge this zone's range of PFNs with the existing one */
-+              if (zone_start < ext->start)
-+                      ext->start = zone_start;
-+              if (zone_end > ext->end)
-+                      ext->end = zone_end;
-+
-+              /* More merging may be possible */
-+              cur = ext;
-+              list_for_each_entry_safe_continue(cur, aux, list, hook) {
-+                      if (zone_end < cur->start)
-+                              break;
-+                      if (zone_end < cur->end)
-+                              ext->end = cur->end;
-+                      list_del(&cur->hook);
-+                      kfree(cur);
-+              }
-       }
--      return zbmlist;
-+
-+      return 0;
- }
- /**
-   *   memory_bm_create - allocate memory for a memory bitmap
-   */
--
- static int
- memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed)
- {
-       struct chain_allocator ca;
--      struct zone *zone;
--      struct zone_bitmap *zone_bm;
--      struct bm_block *bb;
--      unsigned int nr;
-+      struct list_head mem_extents;
-+      struct mem_extent *ext;
-+      int error;
-       chain_init(&ca, gfp_mask, safe_needed);
-+      INIT_LIST_HEAD(&bm->blocks);
--      /* Compute the number of zones */
--      nr = 0;
--      for_each_zone(zone)
--              if (populated_zone(zone))
--                      nr++;
--
--      /* Allocate the list of zones bitmap objects */
--      zone_bm = create_zone_bm_list(nr, &ca);
--      bm->zone_bm_list = zone_bm;
--      if (!zone_bm) {
--              chain_free(&ca, PG_UNSAFE_CLEAR);
--              return -ENOMEM;
--      }
-+      error = create_mem_extents(&mem_extents, gfp_mask);
-+      if (error)
-+              return error;
--      /* Initialize the zone bitmap objects */
--      for_each_zone(zone) {
--              unsigned long pfn;
-+      list_for_each_entry(ext, &mem_extents, hook) {
-+              struct bm_block *bb;
-+              unsigned long pfn = ext->start;
-+              unsigned long pages = ext->end - ext->start;
--              if (!populated_zone(zone))
--                      continue;
-+              bb = list_entry(bm->blocks.prev, struct bm_block, hook);
--              zone_bm->start_pfn = zone->zone_start_pfn;
--              zone_bm->end_pfn = zone->zone_start_pfn + zone->spanned_pages;
--              /* Allocate the list of bitmap block objects */
--              nr = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK);
--              bb = create_bm_block_list(nr, &ca);
--              zone_bm->bm_blocks = bb;
--              zone_bm->cur_block = bb;
--              if (!bb)
--                      goto Free;
-+              error = create_bm_block_list(pages, bm->blocks.prev, &ca);
-+              if (error)
-+                      goto Error;
--              nr = zone->spanned_pages;
--              pfn = zone->zone_start_pfn;
--              /* Initialize the bitmap block objects */
--              while (bb) {
--                      unsigned long *ptr;
--
--                      ptr = get_image_page(gfp_mask, safe_needed);
--                      bb->data = ptr;
--                      if (!ptr)
--                              goto Free;
-+              list_for_each_entry_continue(bb, &bm->blocks, hook) {
-+                      bb->data = get_image_page(gfp_mask, safe_needed);
-+                      if (!bb->data) {
-+                              error = -ENOMEM;
-+                              goto Error;
-+                      }
-                       bb->start_pfn = pfn;
--                      if (nr >= BM_BITS_PER_BLOCK) {
-+                      if (pages >= BM_BITS_PER_BLOCK) {
-                               pfn += BM_BITS_PER_BLOCK;
--                              nr -= BM_BITS_PER_BLOCK;
-+                              pages -= BM_BITS_PER_BLOCK;
-                       } else {
-                               /* This is executed only once in the loop */
--                              pfn += nr;
-+                              pfn += pages;
-                       }
-                       bb->end_pfn = pfn;
--                      bb = bb->next;
-               }
--              zone_bm = zone_bm->next;
-       }
-+
-       bm->p_list = ca.chain;
-       memory_bm_position_reset(bm);
--      return 0;
-+ Exit:
-+      free_mem_extents(&mem_extents);
-+      return error;
-- Free:
-+ Error:
-       bm->p_list = ca.chain;
-       memory_bm_free(bm, PG_UNSAFE_CLEAR);
--      return -ENOMEM;
-+      goto Exit;
- }
- /**
-   *   memory_bm_free - free memory occupied by the memory bitmap @bm
-   */
--
- static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
- {
--      struct zone_bitmap *zone_bm;
-+      struct bm_block *bb;
--      /* Free the list of bit blocks for each zone_bitmap object */
--      zone_bm = bm->zone_bm_list;
--      while (zone_bm) {
--              struct bm_block *bb;
-+      list_for_each_entry(bb, &bm->blocks, hook)
-+              if (bb->data)
-+                      free_image_page(bb->data, clear_nosave_free);
--              bb = zone_bm->bm_blocks;
--              while (bb) {
--                      if (bb->data)
--                              free_image_page(bb->data, clear_nosave_free);
--                      bb = bb->next;
--              }
--              zone_bm = zone_bm->next;
--      }
-       free_list_of_pages(bm->p_list, clear_nosave_free);
--      bm->zone_bm_list = NULL;
-+
-+      INIT_LIST_HEAD(&bm->blocks);
- }
- /**
-@@ -437,38 +452,33 @@ static void memory_bm_free(struct memory
-  *    to given pfn.  The cur_zone_bm member of @bm and the cur_block member
-  *    of @bm->cur_zone_bm are updated.
-  */
--
- static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
-                               void **addr, unsigned int *bit_nr)
- {
--      struct zone_bitmap *zone_bm;
-       struct bm_block *bb;
--      /* Check if the pfn is from the current zone */
--      zone_bm = bm->cur.zone_bm;
--      if (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) {
--              zone_bm = bm->zone_bm_list;
--              /* We don't assume that the zones are sorted by pfns */
--              while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) {
--                      zone_bm = zone_bm->next;
--
--                      if (!zone_bm)
--                              return -EFAULT;
--              }
--              bm->cur.zone_bm = zone_bm;
--      }
--      /* Check if the pfn corresponds to the current bitmap block */
--      bb = zone_bm->cur_block;
-+      /*
-+       * Check if the pfn corresponds to the current bitmap block and find
-+       * the block where it fits if this is not the case.
-+       */
-+      bb = bm->cur.block;
-       if (pfn < bb->start_pfn)
--              bb = zone_bm->bm_blocks;
-+              list_for_each_entry_continue_reverse(bb, &bm->blocks, hook)
-+                      if (pfn >= bb->start_pfn)
-+                              break;
-+
-+      if (pfn >= bb->end_pfn)
-+              list_for_each_entry_continue(bb, &bm->blocks, hook)
-+                      if (pfn >= bb->start_pfn && pfn < bb->end_pfn)
-+                              break;
--      while (pfn >= bb->end_pfn) {
--              bb = bb->next;
-+      if (&bb->hook == &bm->blocks)
-+              return -EFAULT;
--              BUG_ON(!bb);
--      }
--      zone_bm->cur_block = bb;
-+      /* The block has been found */
-+      bm->cur.block = bb;
-       pfn -= bb->start_pfn;
-+      bm->cur.bit = pfn + 1;
-       *bit_nr = pfn;
-       *addr = bb->data;
-       return 0;
-@@ -530,29 +540,21 @@ static int memory_bm_test_bit(struct mem
- static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm)
- {
--      struct zone_bitmap *zone_bm;
-       struct bm_block *bb;
-       int bit;
-+      bb = bm->cur.block;
-       do {
--              bb = bm->cur.block;
--              do {
--                      bit = bm->cur.bit;
--                      bit = find_next_bit(bb->data, bm_block_bits(bb), bit);
--                      if (bit < bm_block_bits(bb))
--                              goto Return_pfn;
--
--                      bb = bb->next;
--                      bm->cur.block = bb;
--                      bm->cur.bit = 0;
--              } while (bb);
--              zone_bm = bm->cur.zone_bm->next;
--              if (zone_bm) {
--                      bm->cur.zone_bm = zone_bm;
--                      bm->cur.block = zone_bm->bm_blocks;
--                      bm->cur.bit = 0;
--              }
--      } while (zone_bm);
-+              bit = bm->cur.bit;
-+              bit = find_next_bit(bb->data, bm_block_bits(bb), bit);
-+              if (bit < bm_block_bits(bb))
-+                      goto Return_pfn;
-+
-+              bb = list_entry(bb->hook.next, struct bm_block, hook);
-+              bm->cur.block = bb;
-+              bm->cur.bit = 0;
-+      } while (&bb->hook != &bm->blocks);
-+
-       memory_bm_position_reset(bm);
-       return BM_END_OF_MAP;
-@@ -808,8 +810,7 @@ static unsigned int count_free_highmem_p
-  *    We should save the page if it isn't Nosave or NosaveFree, or Reserved,
-  *    and it isn't a part of a free chunk of pages.
-  */
--
--static struct page *saveable_highmem_page(unsigned long pfn)
-+static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
- {
-       struct page *page;
-@@ -817,6 +818,8 @@ static struct page *saveable_highmem_pag
-               return NULL;
-       page = pfn_to_page(pfn);
-+      if (page_zone(page) != zone)
-+              return NULL;
-       BUG_ON(!PageHighMem(page));
-@@ -846,13 +849,16 @@ unsigned int count_highmem_pages(void)
-               mark_free_pages(zone);
-               max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
-               for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
--                      if (saveable_highmem_page(pfn))
-+                      if (saveable_highmem_page(zone, pfn))
-                               n++;
-       }
-       return n;
- }
- #else
--static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
-+static inline void *saveable_highmem_page(struct zone *z, unsigned long p)
-+{
-+      return NULL;
-+}
- #endif /* CONFIG_HIGHMEM */
- /**
-@@ -863,8 +869,7 @@ static inline void *saveable_highmem_pag
-  *    of pages statically defined as 'unsaveable', and it isn't a part of
-  *    a free chunk of pages.
-  */
--
--static struct page *saveable_page(unsigned long pfn)
-+static struct page *saveable_page(struct zone *zone, unsigned long pfn)
- {
-       struct page *page;
-@@ -872,6 +877,8 @@ static struct page *saveable_page(unsign
-               return NULL;
-       page = pfn_to_page(pfn);
-+      if (page_zone(page) != zone)
-+              return NULL;
-       BUG_ON(PageHighMem(page));
-@@ -903,7 +910,7 @@ unsigned int count_data_pages(void)
-               mark_free_pages(zone);
-               max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
-               for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
--                      if(saveable_page(pfn))
-+                      if (saveable_page(zone, pfn))
-                               n++;
-       }
-       return n;
-@@ -944,7 +951,7 @@ static inline struct page *
- page_is_saveable(struct zone *zone, unsigned long pfn)
- {
-       return is_highmem(zone) ?
--                      saveable_highmem_page(pfn) : saveable_page(pfn);
-+              saveable_highmem_page(zone, pfn) : saveable_page(zone, pfn);
- }
- static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
-@@ -975,7 +982,7 @@ static void copy_data_page(unsigned long
-       }
- }
- #else
--#define page_is_saveable(zone, pfn)   saveable_page(pfn)
-+#define page_is_saveable(zone, pfn)   saveable_page(zone, pfn)
- static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
- {