-static int write_suspend_image(void)
-{
- int i;
- swp_entry_t entry, prev = { 0 };
- int nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
- union diskpage *cur, *buffer = (union diskpage *)get_zeroed_page(GFP_ATOMIC);
- unsigned long address;
- struct page *page;
-
- if (!buffer)
- return -ENOMEM;
-
- printk( "Writing data to swap (%d pages): ", nr_copy_pages );
- for (i=0; i<nr_copy_pages; i++) {
- if (!(i%100))
- printk( "." );
- if (!(entry = get_swap_page()).val)
- panic("\nNot enough swapspace when writing data" );
-
- if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
- panic("\nPage %d: not enough swapspace on suspend device", i );
-
- address = (pagedir_nosave+i)->address;
- page = virt_to_page(address);
- rw_swap_page_sync(WRITE, entry, page);
- (pagedir_nosave+i)->swap_address = entry;
- }
- printk( "|\n" );
- printk( "Writing pagedir (%d pages): ", nr_pgdir_pages);
- for (i=0; i<nr_pgdir_pages; i++) {
- cur = (union diskpage *)((char *) pagedir_nosave)+i;
- BUG_ON ((char *) cur != (((char *) pagedir_nosave) + i*PAGE_SIZE));
- printk( "." );
- if (!(entry = get_swap_page()).val) {
- printk(KERN_CRIT "Not enough swapspace when writing pgdir\n" );
- panic("Don't know how to recover");
- free_page((unsigned long) buffer);
- return -ENOSPC;
- }
-
- if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
- panic("\nNot enough swapspace for pagedir on suspend device" );
-
- BUG_ON (sizeof(swp_entry_t) != sizeof(long));
- BUG_ON (PAGE_SIZE % sizeof(struct pbe));
-
- cur->link.next = prev;
- page = virt_to_page((unsigned long)cur);
- rw_swap_page_sync(WRITE, entry, page);
- prev = entry;
- }
- printk("H");
- BUG_ON (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t));
- BUG_ON (sizeof(union diskpage) != PAGE_SIZE);
- BUG_ON (sizeof(struct link) != PAGE_SIZE);
- if (!(entry = get_swap_page()).val)
- panic( "\nNot enough swapspace when writing header" );
- if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
- panic("\nNot enough swapspace for header on suspend device" );
-
- cur = (void *) buffer;
- if (fill_suspend_header(&cur->sh))
- BUG(); /* Not a BUG_ON(): we want fill_suspend_header to be called, always */
-
- cur->link.next = prev;
-
- page = virt_to_page((unsigned long)cur);
- rw_swap_page_sync(WRITE, entry, page);
- prev = entry;
-
- printk( "S" );
- mark_swapfiles(prev, MARK_SWAP_SUSPEND);
- printk( "|\n" );
-
- MDELAY(1000);
- return 0;
-}
-
-#ifdef CONFIG_HIGHMEM
-struct highmem_page {
- char *data;
- struct page *page;
- struct highmem_page *next;
-};
-
-struct highmem_page *highmem_copy = NULL;
-
-static int save_highmem_zone(struct zone *zone)
-{
- unsigned long zone_pfn;
- for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
- struct page *page;
- struct highmem_page *save;
- void *kaddr;
- unsigned long pfn = zone_pfn + zone->zone_start_pfn;
- int chunk_size;
-
- if (!(pfn%1000))
- printk(".");
- if (!pfn_valid(pfn))
- 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.
- */
- if (PageReserved(page)) {
- printk("highmem reserved page?!\n");
- continue;
- }
- if ((chunk_size = is_head_of_free_region(page))) {
- pfn += chunk_size - 1;
- zone_pfn += chunk_size - 1;
- continue;
- }
- save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC);
- if (!save)
- return -ENOMEM;
- save->next = highmem_copy;
- save->page = page;
- save->data = (void *) get_zeroed_page(GFP_ATOMIC);
- if (!save->data) {
- kfree(save);
- return -ENOMEM;
- }
- kaddr = kmap_atomic(page, KM_USER0);
- memcpy(save->data, kaddr, PAGE_SIZE);
- kunmap_atomic(kaddr, KM_USER0);
- highmem_copy = save;
- }
- return 0;
-}
-
-static int save_highmem(void)
-{
- struct zone *zone;
- int res = 0;
- for_each_zone(zone) {
- if (is_highmem(zone))
- res = save_highmem_zone(zone);
- if (res)
- return res;
- }
- return 0;
-}
-
-static int restore_highmem(void)
-{
- while (highmem_copy) {
- struct highmem_page *save = highmem_copy;
- void *kaddr;
- highmem_copy = save->next;
-
- kaddr = kmap_atomic(save->page, KM_USER0);
- memcpy(kaddr, save->data, PAGE_SIZE);
- kunmap_atomic(kaddr, KM_USER0);
- free_page((long) save->data);
- kfree(save);
- }
- return 0;
-}
-#endif
-
-static int pfn_is_nosave(unsigned long pfn)
-{
- unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
- unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
- return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
-}