]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/power/snapshot.c
PCI: remove parisc consumer of the pci global_list
[linux-2.6-omap-h63xx.git] / kernel / power / snapshot.c
index 95250d7c8d91db36593fc3707b10c99a8370dc62..5f91a07c4eac7e104f3fc9c333a481be11ead921 100644 (file)
@@ -447,7 +447,7 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
  *     of @bm->cur_zone_bm are updated.
  */
 
-static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
+static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
                                void **addr, unsigned int *bit_nr)
 {
        struct zone_bitmap *zone_bm;
@@ -461,7 +461,8 @@ static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
                while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) {
                        zone_bm = zone_bm->next;
 
-                       BUG_ON(!zone_bm);
+                       if (!zone_bm)
+                               return -EFAULT;
                }
                bm->cur.zone_bm = zone_bm;
        }
@@ -479,23 +480,40 @@ static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
        pfn -= bb->start_pfn;
        *bit_nr = pfn % BM_BITS_PER_CHUNK;
        *addr = bb->data + pfn / BM_BITS_PER_CHUNK;
+       return 0;
 }
 
 static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
 {
        void *addr;
        unsigned int bit;
+       int error;
 
-       memory_bm_find_bit(bm, pfn, &addr, &bit);
+       error = memory_bm_find_bit(bm, pfn, &addr, &bit);
+       BUG_ON(error);
        set_bit(bit, addr);
 }
 
+static int mem_bm_set_bit_check(struct memory_bitmap *bm, unsigned long pfn)
+{
+       void *addr;
+       unsigned int bit;
+       int error;
+
+       error = memory_bm_find_bit(bm, pfn, &addr, &bit);
+       if (!error)
+               set_bit(bit, addr);
+       return error;
+}
+
 static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
 {
        void *addr;
        unsigned int bit;
+       int error;
 
-       memory_bm_find_bit(bm, pfn, &addr, &bit);
+       error = memory_bm_find_bit(bm, pfn, &addr, &bit);
+       BUG_ON(error);
        clear_bit(bit, addr);
 }
 
@@ -503,8 +521,10 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
 {
        void *addr;
        unsigned int bit;
+       int error;
 
-       memory_bm_find_bit(bm, pfn, &addr, &bit);
+       error = memory_bm_find_bit(bm, pfn, &addr, &bit);
+       BUG_ON(error);
        return test_bit(bit, addr);
 }
 
@@ -709,8 +729,15 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
                                region->end_pfn << PAGE_SHIFT);
 
                for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
-                       if (pfn_valid(pfn))
-                               memory_bm_set_bit(bm, pfn);
+                       if (pfn_valid(pfn)) {
+                               /*
+                                * It is safe to ignore the result of
+                                * mem_bm_set_bit_check() here, since we won't
+                                * touch the PFNs for which the error is
+                                * returned anyway.
+                                */
+                               mem_bm_set_bit_check(bm, pfn);
+                       }
        }
 }
 
@@ -875,8 +902,8 @@ static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
 #endif /* CONFIG_HIGHMEM */
 
 /**
- *     saveable - Determine whether a non-highmem page should be included in
- *     the suspend image.
+ *     saveable_page - Determine whether a non-highmem page should be included
+ *     in the suspend image.
  *
  *     We should save the page if it isn't Nosave, and is not in the range
  *     of pages statically defined as 'unsaveable', and it isn't a part of
@@ -897,7 +924,8 @@ static struct page *saveable_page(unsigned long pfn)
        if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
                return NULL;
 
-       if (PageReserved(page) && pfn_is_nosave(pfn))
+       if (PageReserved(page)
+           && (!kernel_page_present(page) || pfn_is_nosave(pfn)))
                return NULL;
 
        return page;
@@ -938,6 +966,25 @@ static inline void do_copy_page(long *dst, long *src)
                *dst++ = *src++;
 }
 
+
+/**
+ *     safe_copy_page - check if the page we are going to copy is marked as
+ *             present in the kernel page tables (this always is the case if
+ *             CONFIG_DEBUG_PAGEALLOC is not set and in that case
+ *             kernel_page_present() always returns 'true').
+ */
+static void safe_copy_page(void *dst, struct page *s_page)
+{
+       if (kernel_page_present(s_page)) {
+               do_copy_page(dst, page_address(s_page));
+       } else {
+               kernel_map_pages(s_page, 1, 1);
+               do_copy_page(dst, page_address(s_page));
+               kernel_map_pages(s_page, 1, 0);
+       }
+}
+
+
 #ifdef CONFIG_HIGHMEM
 static inline struct page *
 page_is_saveable(struct zone *zone, unsigned long pfn)
@@ -946,8 +993,7 @@ page_is_saveable(struct zone *zone, unsigned long pfn)
                        saveable_highmem_page(pfn) : saveable_page(pfn);
 }
 
-static inline void
-copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
+static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
 {
        struct page *s_page, *d_page;
        void *src, *dst;
@@ -961,29 +1007,26 @@ copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
                kunmap_atomic(src, KM_USER0);
                kunmap_atomic(dst, KM_USER1);
        } else {
-               src = page_address(s_page);
                if (PageHighMem(d_page)) {
                        /* Page pointed to by src may contain some kernel
                         * data modified by kmap_atomic()
                         */
-                       do_copy_page(buffer, src);
+                       safe_copy_page(buffer, s_page);
                        dst = kmap_atomic(pfn_to_page(dst_pfn), KM_USER0);
                        memcpy(dst, buffer, PAGE_SIZE);
                        kunmap_atomic(dst, KM_USER0);
                } else {
-                       dst = page_address(d_page);
-                       do_copy_page(dst, src);
+                       safe_copy_page(page_address(d_page), s_page);
                }
        }
 }
 #else
 #define page_is_saveable(zone, pfn)    saveable_page(pfn)
 
-static inline void
-copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
+static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
 {
-       do_copy_page(page_address(pfn_to_page(dst_pfn)),
-                       page_address(pfn_to_page(src_pfn)));
+       safe_copy_page(page_address(pfn_to_page(dst_pfn)),
+                               pfn_to_page(src_pfn));
 }
 #endif /* CONFIG_HIGHMEM */