Pull hp-machvec into release branch
[powerpc.git] / kernel / power / swsusp.c
index d967e87..2d5c456 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};
        }
 }
 
@@ -863,6 +862,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 +920,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 +931,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 +947,6 @@ static int swsusp_alloc(void)
                return error;
        }
 
-       nr_copy_pages_check = nr_copy_pages;
        return 0;
 }
 
@@ -1089,7 +1095,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(unsigned gfp_mask)
 {
        unsigned long m;
 
@@ -1103,7 +1109,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 +1219,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 +1441,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 +1481,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);