]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - kernel/power/swsusp.c
[PATCH] core remove PageReserved
[mirror_ubuntu-zesty-kernel.git] / kernel / power / swsusp.c
index d967e875ee82f974d9f4e8e365aa59270a6f5c61..016504ccfccf4e6e37d97015d0f4026a51d52299 100644 (file)
@@ -363,7 +363,7 @@ static void lock_swapdevices(void)
 }
 
 /**
- *     write_swap_page - Write one page to a fresh swap location.
+ *     write_page - Write one page to a fresh swap location.
  *     @addr:  Address we're writing.
  *     @loc:   Place to store the entry we used.
  *
@@ -402,15 +402,14 @@ static int write_page(unsigned long addr, swp_entry_t * loc)
 static void data_free(void)
 {
        swp_entry_t entry;
-       int i;
+       struct pbe * p;
 
-       for (i = 0; i < nr_copy_pages; i++) {
-               entry = (pagedir_nosave + i)->swap_address;
+       for_each_pbe(p, pagedir_nosave) {
+               entry = p->swap_address;
                if (entry.val)
                        swap_free(entry);
                else
                        break;
-               (pagedir_nosave + i)->swap_address = (swp_entry_t){0};
        }
 }
 
@@ -579,15 +578,23 @@ static int save_highmem_zone(struct zone *zone)
                        continue;
                page = pfn_to_page(pfn);
                /*
-                * This condition results from rvmalloc() sans vmalloc_32()
-                * and architectural memory reservations. This should be
-                * corrected eventually when the cases giving rise to this
-                * are better understood.
+                * PageReserved results from rvmalloc() sans vmalloc_32()
+                * and architectural memory reservations.
+                *
+                * rvmalloc should not cause this, because all implementations
+                * appear to always be using vmalloc_32 on architectures with
+                * highmem. This is a good thing, because we would like to save
+                * rvmalloc pages.
+                *
+                * It appears to be triggered by pages which do not point to
+                * valid memory (see arch/i386/mm/init.c:one_highpage_init(),
+                * which sets PageReserved if the page does not point to valid
+                * RAM.
+                *
+                * XXX: must remove usage of PageReserved!
                 */
-               if (PageReserved(page)) {
-                       printk("highmem reserved page?!\n");
+               if (PageReserved(page))
                        continue;
-               }
                BUG_ON(PageNosave(page));
                if (PageNosaveFree(page))
                        continue;
@@ -673,10 +680,9 @@ static int saveable(struct zone * zone, unsigned long * zone_pfn)
                return 0;
 
        page = pfn_to_page(pfn);
-       BUG_ON(PageReserved(page) && PageNosave(page));
        if (PageNosave(page))
                return 0;
-       if (PageReserved(page) && pfn_is_nosave(pfn)) {
+       if (pfn_is_nosave(pfn)) {
                pr_debug("[nosave pfn 0x%lx]", pfn);
                return 0;
        }
@@ -863,6 +869,9 @@ static int alloc_image_pages(void)
        return 0;
 }
 
+/* Free pages we allocated for suspend. Suspend pages are alocated
+ * before atomic copy, so we need to free them after resume.
+ */
 void swsusp_free(void)
 {
        BUG_ON(PageNosave(virt_to_page(pagedir_save)));
@@ -918,6 +927,7 @@ static int swsusp_alloc(void)
 
        pagedir_nosave = NULL;
        nr_copy_pages = calc_nr(nr_copy_pages);
+       nr_copy_pages_check = nr_copy_pages;
 
        pr_debug("suspend: (pages needed: %d + %d free: %d)\n",
                 nr_copy_pages, PAGES_FOR_IO, nr_free_pages());
@@ -928,6 +938,10 @@ static int swsusp_alloc(void)
        if (!enough_swap())
                return -ENOSPC;
 
+       if (MAX_PBES < nr_copy_pages / PBES_PER_PAGE +
+           !!(nr_copy_pages % PBES_PER_PAGE))
+               return -ENOSPC;
+
        if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) {
                printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
                return -ENOMEM;
@@ -940,7 +954,6 @@ static int swsusp_alloc(void)
                return error;
        }
 
-       nr_copy_pages_check = nr_copy_pages;
        return 0;
 }
 
@@ -1089,7 +1102,7 @@ static inline void eat_page(void *page)
        *eaten_memory = c;
 }
 
-static unsigned long get_usable_page(unsigned gfp_mask)
+unsigned long get_usable_page(gfp_t gfp_mask)
 {
        unsigned long m;
 
@@ -1103,7 +1116,7 @@ static unsigned long get_usable_page(unsigned gfp_mask)
        return m;
 }
 
-static void free_eaten_memory(void)
+void free_eaten_memory(void)
 {
        unsigned long m;
        void **c;
@@ -1213,8 +1226,9 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
                free_pagedir(pblist);
                free_eaten_memory();
                pblist = NULL;
-       }
-       else
+               /* Is this even worth handling? It should never ever happen, and we
+                  have just lost user's state, anyway... */
+       } else
                printk("swsusp: Relocated %d pages\n", rel);
 
        return pblist;
@@ -1434,9 +1448,9 @@ static int read_pagedir(struct pbe *pblist)
        }
 
        if (error)
-               free_page((unsigned long)pblist);
-
-       BUG_ON(i != swsusp_info.pagedir_pages);
+               free_pagedir(pblist);
+       else
+               BUG_ON(i != swsusp_info.pagedir_pages);
 
        return error;
 }
@@ -1474,11 +1488,12 @@ static int read_suspend_image(void)
        /* Allocate memory for the image and read the data from swap */
 
        error = check_pagedir(pagedir_nosave);
-       free_eaten_memory();
+
        if (!error)
                error = data_read(pagedir_nosave);
 
        if (error) { /* We fail cleanly */
+               free_eaten_memory();
                for_each_pbe (p, pagedir_nosave)
                        if (p->address) {
                                free_page(p->address);