/* * linux/kernel/power/swap.c * * This file provides functions for reading the suspend image from * and writing it to a swap partition. * * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> * Copyright (C) 2010-2012 Bojan Smojver <bojan@rexursive.com> * * This file is released under the GPLv2. * */#include <linux/module.h>#include <linux/file.h>#include <linux/delay.h>#include <linux/bitops.h>#include <linux/genhd.h>#include <linux/device.h>#include <linux/bio.h>#include <linux/blkdev.h>#include <linux/swap.h>#include <linux/swapops.h>#include <linux/pm.h>#include <linux/slab.h>#include <linux/lzo.h>#include <linux/vmalloc.h>#include <linux/cpumask.h>#include <linux/atomic.h>#include <linux/kthread.h>#include <linux/crc32.h>#include"power.h"#define HIBERNATE_SIG"S1SUSPEND"/* * The swap map is a data structure used for keeping track of each page * written to a swap partition. It consists of many swap_map_page * structures that contain each an array of MAP_PAGE_ENTRIES swap entries. * These structures are stored on the swap and linked together with the * help of the .next_swap member. * * The swap map is created during suspend. The swap map pages are * allocated and populated one at a time, so we only need one memory * page to set up the entire structure. * * During resume we pick up all swap_map_page structures into a list. */#define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1)/* * Number of free pages that are not high. */staticinlineunsigned longlow_free_pages(void){returnnr_free_pages() -nr_free_highpages();}/* * Number of pages required to be kept free while writing the image. Always * half of all available low pages before the writing starts. */staticinlineunsigned longreqd_free_pages(void){returnlow_free_pages() /2;}struct swap_map_page {
sector_t entries[MAP_PAGE_ENTRIES];
sector_t next_swap;};struct swap_map_page_list {struct swap_map_page *map;struct swap_map_page_list *next;};/** * The swap_map_handle structure is used for handling swap in * a file-alike way */struct swap_map_handle {struct swap_map_page *cur;struct swap_map_page_list *maps;
sector_t cur_swap;
sector_t first_sector;unsigned int k;unsigned long reqd_free_pages;
u32 crc32;};struct swsusp_header {char reserved[PAGE_SIZE -20-sizeof(sector_t) -sizeof(int) -sizeof(u32)];
u32 crc32;
sector_t image;unsigned int flags;/* Flags to pass to the "boot" kernel */char orig_sig[10];char sig[10];}__attribute__((packed));static struct swsusp_header *swsusp_header;/** * The following functions are used for tracing the allocated * swap pages, so that they can be freed in case of an error. */struct swsusp_extent {struct rb_node node;unsigned long start;unsigned long end;};static struct rb_root swsusp_extents = RB_ROOT;static intswsusp_extents_insert(unsigned long swap_offset){struct rb_node **new= &(swsusp_extents.rb_node);struct rb_node *parent = NULL;struct swsusp_extent *ext;/* Figure out where to put the new node */while(*new) {
ext =container_of(*new,struct swsusp_extent, node);
parent = *new;if(swap_offset < ext->start) {/* Try to merge */if