xref: /openbmc/linux/kernel/power/swap.c (revision a2531293)
161159a31SRafael J. Wysocki /*
261159a31SRafael J. Wysocki  * linux/kernel/power/swap.c
361159a31SRafael J. Wysocki  *
461159a31SRafael J. Wysocki  * This file provides functions for reading the suspend image from
561159a31SRafael J. Wysocki  * and writing it to a swap partition.
661159a31SRafael J. Wysocki  *
7a2531293SPavel Machek  * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
861159a31SRafael J. Wysocki  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
961159a31SRafael J. Wysocki  *
1061159a31SRafael J. Wysocki  * This file is released under the GPLv2.
1161159a31SRafael J. Wysocki  *
1261159a31SRafael J. Wysocki  */
1361159a31SRafael J. Wysocki 
1461159a31SRafael J. Wysocki #include <linux/module.h>
1561159a31SRafael J. Wysocki #include <linux/file.h>
1661159a31SRafael J. Wysocki #include <linux/delay.h>
1761159a31SRafael J. Wysocki #include <linux/bitops.h>
1861159a31SRafael J. Wysocki #include <linux/genhd.h>
1961159a31SRafael J. Wysocki #include <linux/device.h>
2061159a31SRafael J. Wysocki #include <linux/buffer_head.h>
2161159a31SRafael J. Wysocki #include <linux/bio.h>
22546e0d27SAndrew Morton #include <linux/blkdev.h>
2361159a31SRafael J. Wysocki #include <linux/swap.h>
2461159a31SRafael J. Wysocki #include <linux/swapops.h>
2561159a31SRafael J. Wysocki #include <linux/pm.h>
265a0e3ad6STejun Heo #include <linux/slab.h>
2761159a31SRafael J. Wysocki 
2861159a31SRafael J. Wysocki #include "power.h"
2961159a31SRafael J. Wysocki 
3061159a31SRafael J. Wysocki #define SWSUSP_SIG	"S1SUSPEND"
3161159a31SRafael J. Wysocki 
3251fb352bSJiri Slaby /*
3351fb352bSJiri Slaby  *	The swap map is a data structure used for keeping track of each page
3451fb352bSJiri Slaby  *	written to a swap partition.  It consists of many swap_map_page
3551fb352bSJiri Slaby  *	structures that contain each an array of MAP_PAGE_SIZE swap entries.
3651fb352bSJiri Slaby  *	These structures are stored on the swap and linked together with the
3751fb352bSJiri Slaby  *	help of the .next_swap member.
3851fb352bSJiri Slaby  *
3951fb352bSJiri Slaby  *	The swap map is created during suspend.  The swap map pages are
4051fb352bSJiri Slaby  *	allocated and populated one at a time, so we only need one memory
4151fb352bSJiri Slaby  *	page to set up the entire structure.
4251fb352bSJiri Slaby  *
4351fb352bSJiri Slaby  *	During resume we also only need to use one swap_map_page structure
4451fb352bSJiri Slaby  *	at a time.
4551fb352bSJiri Slaby  */
4651fb352bSJiri Slaby 
4751fb352bSJiri Slaby #define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
4851fb352bSJiri Slaby 
4951fb352bSJiri Slaby struct swap_map_page {
5051fb352bSJiri Slaby 	sector_t entries[MAP_PAGE_ENTRIES];
5151fb352bSJiri Slaby 	sector_t next_swap;
5251fb352bSJiri Slaby };
5351fb352bSJiri Slaby 
5451fb352bSJiri Slaby /**
5551fb352bSJiri Slaby  *	The swap_map_handle structure is used for handling swap in
5651fb352bSJiri Slaby  *	a file-alike way
5751fb352bSJiri Slaby  */
5851fb352bSJiri Slaby 
5951fb352bSJiri Slaby struct swap_map_handle {
6051fb352bSJiri Slaby 	struct swap_map_page *cur;
6151fb352bSJiri Slaby 	sector_t cur_swap;
6251fb352bSJiri Slaby 	sector_t first_sector;
6351fb352bSJiri Slaby 	unsigned int k;
6451fb352bSJiri Slaby };
6551fb352bSJiri Slaby 
661b29c164SVivek Goyal struct swsusp_header {
67a634cc10SRafael J. Wysocki 	char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
683aef83e0SRafael J. Wysocki 	sector_t image;
69a634cc10SRafael J. Wysocki 	unsigned int flags;	/* Flags to pass to the "boot" kernel */
7061159a31SRafael J. Wysocki 	char	orig_sig[10];
7161159a31SRafael J. Wysocki 	char	sig[10];
721b29c164SVivek Goyal } __attribute__((packed));
731b29c164SVivek Goyal 
741b29c164SVivek Goyal static struct swsusp_header *swsusp_header;
7561159a31SRafael J. Wysocki 
760414f2ecSNigel Cunningham /**
770414f2ecSNigel Cunningham  *	The following functions are used for tracing the allocated
780414f2ecSNigel Cunningham  *	swap pages, so that they can be freed in case of an error.
790414f2ecSNigel Cunningham  */
800414f2ecSNigel Cunningham 
810414f2ecSNigel Cunningham struct swsusp_extent {
820414f2ecSNigel Cunningham 	struct rb_node node;
830414f2ecSNigel Cunningham 	unsigned long start;
840414f2ecSNigel Cunningham 	unsigned long end;
850414f2ecSNigel Cunningham };
860414f2ecSNigel Cunningham 
870414f2ecSNigel Cunningham static struct rb_root swsusp_extents = RB_ROOT;
880414f2ecSNigel Cunningham 
890414f2ecSNigel Cunningham static int swsusp_extents_insert(unsigned long swap_offset)
900414f2ecSNigel Cunningham {
910414f2ecSNigel Cunningham 	struct rb_node **new = &(swsusp_extents.rb_node);
920414f2ecSNigel Cunningham 	struct rb_node *parent = NULL;
930414f2ecSNigel Cunningham 	struct swsusp_extent *ext;
940414f2ecSNigel Cunningham 
950414f2ecSNigel Cunningham 	/* Figure out where to put the new node */
960414f2ecSNigel Cunningham 	while (*new) {
970414f2ecSNigel Cunningham 		ext = container_of(*new, struct swsusp_extent, node);
980414f2ecSNigel Cunningham 		parent = *new;
990414f2ecSNigel Cunningham 		if (swap_offset < ext->start) {
1000414f2ecSNigel Cunningham 			/* Try to merge */
1010414f2ecSNigel Cunningham 			if (swap_offset == ext->start - 1) {
1020414f2ecSNigel Cunningham 				ext->start--;
1030414f2ecSNigel Cunningham 				return 0;
1040414f2ecSNigel Cunningham 			}
1050414f2ecSNigel Cunningham 			new = &((*new)->rb_left);
1060414f2ecSNigel Cunningham 		} else if (swap_offset > ext->end) {
1070414f2ecSNigel Cunningham 			/* Try to merge */
1080414f2ecSNigel Cunningham 			if (swap_offset == ext->end + 1) {
1090414f2ecSNigel Cunningham 				ext->end++;
1100414f2ecSNigel Cunningham 				return 0;
1110414f2ecSNigel Cunningham 			}
1120414f2ecSNigel Cunningham 			new = &((*new)->rb_right);
1130414f2ecSNigel Cunningham 		} else {
1140414f2ecSNigel Cunningham 			/* It already is in the tree */
1150414f2ecSNigel Cunningham 			return -EINVAL;
1160414f2ecSNigel Cunningham 		}
1170414f2ecSNigel Cunningham 	}
1180414f2ecSNigel Cunningham 	/* Add the new node and rebalance the tree. */
1190414f2ecSNigel Cunningham 	ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
1200414f2ecSNigel Cunningham 	if (!ext)
1210414f2ecSNigel Cunningham 		return -ENOMEM;
1220414f2ecSNigel Cunningham 
1230414f2ecSNigel Cunningham 	ext->start = swap_offset;
1240414f2ecSNigel Cunningham 	ext->end = swap_offset;
1250414f2ecSNigel Cunningham 	rb_link_node(&ext->node, parent, new);
1260414f2ecSNigel Cunningham 	rb_insert_color(&ext->node, &swsusp_extents);
1270414f2ecSNigel Cunningham 	return 0;
1280414f2ecSNigel Cunningham }
1290414f2ecSNigel Cunningham 
1300414f2ecSNigel Cunningham /**
1310414f2ecSNigel Cunningham  *	alloc_swapdev_block - allocate a swap page and register that it has
1320414f2ecSNigel Cunningham  *	been allocated, so that it can be freed in case of an error.
1330414f2ecSNigel Cunningham  */
1340414f2ecSNigel Cunningham 
1350414f2ecSNigel Cunningham sector_t alloc_swapdev_block(int swap)
1360414f2ecSNigel Cunningham {
1370414f2ecSNigel Cunningham 	unsigned long offset;
1380414f2ecSNigel Cunningham 
1390414f2ecSNigel Cunningham 	offset = swp_offset(get_swap_page_of_type(swap));
1400414f2ecSNigel Cunningham 	if (offset) {
1410414f2ecSNigel Cunningham 		if (swsusp_extents_insert(offset))
1420414f2ecSNigel Cunningham 			swap_free(swp_entry(swap, offset));
1430414f2ecSNigel Cunningham 		else
1440414f2ecSNigel Cunningham 			return swapdev_block(swap, offset);
1450414f2ecSNigel Cunningham 	}
1460414f2ecSNigel Cunningham 	return 0;
1470414f2ecSNigel Cunningham }
1480414f2ecSNigel Cunningham 
1490414f2ecSNigel Cunningham /**
1500414f2ecSNigel Cunningham  *	free_all_swap_pages - free swap pages allocated for saving image data.
1510414f2ecSNigel Cunningham  *	It also frees the extents used to register which swap entres had been
1520414f2ecSNigel Cunningham  *	allocated.
1530414f2ecSNigel Cunningham  */
1540414f2ecSNigel Cunningham 
1550414f2ecSNigel Cunningham void free_all_swap_pages(int swap)
1560414f2ecSNigel Cunningham {
1570414f2ecSNigel Cunningham 	struct rb_node *node;
1580414f2ecSNigel Cunningham 
1590414f2ecSNigel Cunningham 	while ((node = swsusp_extents.rb_node)) {
1600414f2ecSNigel Cunningham 		struct swsusp_extent *ext;
1610414f2ecSNigel Cunningham 		unsigned long offset;
1620414f2ecSNigel Cunningham 
1630414f2ecSNigel Cunningham 		ext = container_of(node, struct swsusp_extent, node);
1640414f2ecSNigel Cunningham 		rb_erase(node, &swsusp_extents);
1650414f2ecSNigel Cunningham 		for (offset = ext->start; offset <= ext->end; offset++)
1660414f2ecSNigel Cunningham 			swap_free(swp_entry(swap, offset));
1670414f2ecSNigel Cunningham 
1680414f2ecSNigel Cunningham 		kfree(ext);
1690414f2ecSNigel Cunningham 	}
1700414f2ecSNigel Cunningham }
1710414f2ecSNigel Cunningham 
1720414f2ecSNigel Cunningham int swsusp_swap_in_use(void)
1730414f2ecSNigel Cunningham {
1740414f2ecSNigel Cunningham 	return (swsusp_extents.rb_node != NULL);
1750414f2ecSNigel Cunningham }
1760414f2ecSNigel Cunningham 
17761159a31SRafael J. Wysocki /*
1783fc6b34fSRafael J. Wysocki  * General things
17961159a31SRafael J. Wysocki  */
18061159a31SRafael J. Wysocki 
18161159a31SRafael J. Wysocki static unsigned short root_swap = 0xffff;
1828a0d613fSJiri Slaby struct block_device *hib_resume_bdev;
1833fc6b34fSRafael J. Wysocki 
1843fc6b34fSRafael J. Wysocki /*
1853fc6b34fSRafael J. Wysocki  * Saving part
1863fc6b34fSRafael J. Wysocki  */
18761159a31SRafael J. Wysocki 
18851fb352bSJiri Slaby static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
18961159a31SRafael J. Wysocki {
19061159a31SRafael J. Wysocki 	int error;
19161159a31SRafael J. Wysocki 
1928a0d613fSJiri Slaby 	hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
1931b29c164SVivek Goyal 	if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
1941b29c164SVivek Goyal 	    !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
1951b29c164SVivek Goyal 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
1961b29c164SVivek Goyal 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
19751fb352bSJiri Slaby 		swsusp_header->image = handle->first_sector;
198a634cc10SRafael J. Wysocki 		swsusp_header->flags = flags;
1998a0d613fSJiri Slaby 		error = hib_bio_write_page(swsusp_resume_block,
2001b29c164SVivek Goyal 					swsusp_header, NULL);
20161159a31SRafael J. Wysocki 	} else {
20223976728SRafael J. Wysocki 		printk(KERN_ERR "PM: Swap header not found!\n");
20361159a31SRafael J. Wysocki 		error = -ENODEV;
20461159a31SRafael J. Wysocki 	}
20561159a31SRafael J. Wysocki 	return error;
20661159a31SRafael J. Wysocki }
20761159a31SRafael J. Wysocki 
20861159a31SRafael J. Wysocki /**
20961159a31SRafael J. Wysocki  *	swsusp_swap_check - check if the resume device is a swap device
21061159a31SRafael J. Wysocki  *	and get its index (if so)
2116f612af5SJiri Slaby  *
2126f612af5SJiri Slaby  *	This is called before saving image
21361159a31SRafael J. Wysocki  */
2146f612af5SJiri Slaby static int swsusp_swap_check(void)
21561159a31SRafael J. Wysocki {
2163aef83e0SRafael J. Wysocki 	int res;
21761159a31SRafael J. Wysocki 
2187bf23687SRafael J. Wysocki 	res = swap_type_of(swsusp_resume_device, swsusp_resume_block,
2198a0d613fSJiri Slaby 			&hib_resume_bdev);
2203aef83e0SRafael J. Wysocki 	if (res < 0)
2213aef83e0SRafael J. Wysocki 		return res;
2223aef83e0SRafael J. Wysocki 
22361159a31SRafael J. Wysocki 	root_swap = res;
2248a0d613fSJiri Slaby 	res = blkdev_get(hib_resume_bdev, FMODE_WRITE);
2257bf23687SRafael J. Wysocki 	if (res)
2267bf23687SRafael J. Wysocki 		return res;
2273aef83e0SRafael J. Wysocki 
2288a0d613fSJiri Slaby 	res = set_blocksize(hib_resume_bdev, PAGE_SIZE);
2293aef83e0SRafael J. Wysocki 	if (res < 0)
2308a0d613fSJiri Slaby 		blkdev_put(hib_resume_bdev, FMODE_WRITE);
2313aef83e0SRafael J. Wysocki 
23261159a31SRafael J. Wysocki 	return res;
23361159a31SRafael J. Wysocki }
23461159a31SRafael J. Wysocki 
23561159a31SRafael J. Wysocki /**
23661159a31SRafael J. Wysocki  *	write_page - Write one page to given swap location.
23761159a31SRafael J. Wysocki  *	@buf:		Address we're writing.
23861159a31SRafael J. Wysocki  *	@offset:	Offset of the swap page we're writing to.
239ab954160SAndrew Morton  *	@bio_chain:	Link the next write BIO here
24061159a31SRafael J. Wysocki  */
24161159a31SRafael J. Wysocki 
2423aef83e0SRafael J. Wysocki static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
24361159a31SRafael J. Wysocki {
2443aef83e0SRafael J. Wysocki 	void *src;
24561159a31SRafael J. Wysocki 
2463aef83e0SRafael J. Wysocki 	if (!offset)
2473aef83e0SRafael J. Wysocki 		return -ENOSPC;
248ab954160SAndrew Morton 
249ab954160SAndrew Morton 	if (bio_chain) {
25085949121SRafael J. Wysocki 		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
2513aef83e0SRafael J. Wysocki 		if (src) {
2523aef83e0SRafael J. Wysocki 			memcpy(src, buf, PAGE_SIZE);
2533aef83e0SRafael J. Wysocki 		} else {
254ab954160SAndrew Morton 			WARN_ON_ONCE(1);
255ab954160SAndrew Morton 			bio_chain = NULL;	/* Go synchronous */
2563aef83e0SRafael J. Wysocki 			src = buf;
2573aef83e0SRafael J. Wysocki 		}
258ab954160SAndrew Morton 	} else {
2593aef83e0SRafael J. Wysocki 		src = buf;
260ab954160SAndrew Morton 	}
2618a0d613fSJiri Slaby 	return hib_bio_write_page(offset, src, bio_chain);
26261159a31SRafael J. Wysocki }
26361159a31SRafael J. Wysocki 
26461159a31SRafael J. Wysocki static void release_swap_writer(struct swap_map_handle *handle)
26561159a31SRafael J. Wysocki {
26661159a31SRafael J. Wysocki 	if (handle->cur)
26761159a31SRafael J. Wysocki 		free_page((unsigned long)handle->cur);
26861159a31SRafael J. Wysocki 	handle->cur = NULL;
26961159a31SRafael J. Wysocki }
27061159a31SRafael J. Wysocki 
27161159a31SRafael J. Wysocki static int get_swap_writer(struct swap_map_handle *handle)
27261159a31SRafael J. Wysocki {
2736f612af5SJiri Slaby 	int ret;
2746f612af5SJiri Slaby 
2756f612af5SJiri Slaby 	ret = swsusp_swap_check();
2766f612af5SJiri Slaby 	if (ret) {
2776f612af5SJiri Slaby 		if (ret != -ENOSPC)
2786f612af5SJiri Slaby 			printk(KERN_ERR "PM: Cannot find swap device, try "
2796f612af5SJiri Slaby 					"swapon -a.\n");
2806f612af5SJiri Slaby 		return ret;
2816f612af5SJiri Slaby 	}
28261159a31SRafael J. Wysocki 	handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
2836f612af5SJiri Slaby 	if (!handle->cur) {
2846f612af5SJiri Slaby 		ret = -ENOMEM;
2856f612af5SJiri Slaby 		goto err_close;
2866f612af5SJiri Slaby 	}
287d1d241ccSRafael J. Wysocki 	handle->cur_swap = alloc_swapdev_block(root_swap);
28861159a31SRafael J. Wysocki 	if (!handle->cur_swap) {
2896f612af5SJiri Slaby 		ret = -ENOSPC;
2906f612af5SJiri Slaby 		goto err_rel;
29161159a31SRafael J. Wysocki 	}
29261159a31SRafael J. Wysocki 	handle->k = 0;
29351fb352bSJiri Slaby 	handle->first_sector = handle->cur_swap;
29461159a31SRafael J. Wysocki 	return 0;
2956f612af5SJiri Slaby err_rel:
2966f612af5SJiri Slaby 	release_swap_writer(handle);
2976f612af5SJiri Slaby err_close:
2986f612af5SJiri Slaby 	swsusp_close(FMODE_WRITE);
2996f612af5SJiri Slaby 	return ret;
30061159a31SRafael J. Wysocki }
30161159a31SRafael J. Wysocki 
302ab954160SAndrew Morton static int swap_write_page(struct swap_map_handle *handle, void *buf,
303ab954160SAndrew Morton 				struct bio **bio_chain)
304ab954160SAndrew Morton {
305ab954160SAndrew Morton 	int error = 0;
3063aef83e0SRafael J. Wysocki 	sector_t offset;
30761159a31SRafael J. Wysocki 
30861159a31SRafael J. Wysocki 	if (!handle->cur)
30961159a31SRafael J. Wysocki 		return -EINVAL;
310d1d241ccSRafael J. Wysocki 	offset = alloc_swapdev_block(root_swap);
311ab954160SAndrew Morton 	error = write_page(buf, offset, bio_chain);
31261159a31SRafael J. Wysocki 	if (error)
31361159a31SRafael J. Wysocki 		return error;
31461159a31SRafael J. Wysocki 	handle->cur->entries[handle->k++] = offset;
31561159a31SRafael J. Wysocki 	if (handle->k >= MAP_PAGE_ENTRIES) {
3168a0d613fSJiri Slaby 		error = hib_wait_on_bio_chain(bio_chain);
317ab954160SAndrew Morton 		if (error)
318ab954160SAndrew Morton 			goto out;
319d1d241ccSRafael J. Wysocki 		offset = alloc_swapdev_block(root_swap);
32061159a31SRafael J. Wysocki 		if (!offset)
32161159a31SRafael J. Wysocki 			return -ENOSPC;
32261159a31SRafael J. Wysocki 		handle->cur->next_swap = offset;
323ab954160SAndrew Morton 		error = write_page(handle->cur, handle->cur_swap, NULL);
32461159a31SRafael J. Wysocki 		if (error)
325ab954160SAndrew Morton 			goto out;
32661159a31SRafael J. Wysocki 		memset(handle->cur, 0, PAGE_SIZE);
32761159a31SRafael J. Wysocki 		handle->cur_swap = offset;
32861159a31SRafael J. Wysocki 		handle->k = 0;
32961159a31SRafael J. Wysocki 	}
330ab954160SAndrew Morton  out:
331ab954160SAndrew Morton 	return error;
33261159a31SRafael J. Wysocki }
33361159a31SRafael J. Wysocki 
33461159a31SRafael J. Wysocki static int flush_swap_writer(struct swap_map_handle *handle)
33561159a31SRafael J. Wysocki {
33661159a31SRafael J. Wysocki 	if (handle->cur && handle->cur_swap)
337ab954160SAndrew Morton 		return write_page(handle->cur, handle->cur_swap, NULL);
33861159a31SRafael J. Wysocki 	else
33961159a31SRafael J. Wysocki 		return -EINVAL;
34061159a31SRafael J. Wysocki }
34161159a31SRafael J. Wysocki 
3426f612af5SJiri Slaby static int swap_writer_finish(struct swap_map_handle *handle,
3436f612af5SJiri Slaby 		unsigned int flags, int error)
3446f612af5SJiri Slaby {
3456f612af5SJiri Slaby 	if (!error) {
3466f612af5SJiri Slaby 		flush_swap_writer(handle);
3476f612af5SJiri Slaby 		printk(KERN_INFO "PM: S");
3486f612af5SJiri Slaby 		error = mark_swapfiles(handle, flags);
3496f612af5SJiri Slaby 		printk("|\n");
3506f612af5SJiri Slaby 	}
3516f612af5SJiri Slaby 
3526f612af5SJiri Slaby 	if (error)
3536f612af5SJiri Slaby 		free_all_swap_pages(root_swap);
3546f612af5SJiri Slaby 	release_swap_writer(handle);
3556f612af5SJiri Slaby 	swsusp_close(FMODE_WRITE);
3566f612af5SJiri Slaby 
3576f612af5SJiri Slaby 	return error;
3586f612af5SJiri Slaby }
3596f612af5SJiri Slaby 
36061159a31SRafael J. Wysocki /**
36161159a31SRafael J. Wysocki  *	save_image - save the suspend image data
36261159a31SRafael J. Wysocki  */
36361159a31SRafael J. Wysocki 
36461159a31SRafael J. Wysocki static int save_image(struct swap_map_handle *handle,
36561159a31SRafael J. Wysocki                       struct snapshot_handle *snapshot,
3663a4f7577SAndrew Morton                       unsigned int nr_to_write)
36761159a31SRafael J. Wysocki {
36861159a31SRafael J. Wysocki 	unsigned int m;
36961159a31SRafael J. Wysocki 	int ret;
3703a4f7577SAndrew Morton 	int nr_pages;
371ab954160SAndrew Morton 	int err2;
372ab954160SAndrew Morton 	struct bio *bio;
3733a4f7577SAndrew Morton 	struct timeval start;
3743a4f7577SAndrew Morton 	struct timeval stop;
37561159a31SRafael J. Wysocki 
37623976728SRafael J. Wysocki 	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
37723976728SRafael J. Wysocki 		nr_to_write);
3783a4f7577SAndrew Morton 	m = nr_to_write / 100;
37961159a31SRafael J. Wysocki 	if (!m)
38061159a31SRafael J. Wysocki 		m = 1;
38161159a31SRafael J. Wysocki 	nr_pages = 0;
382ab954160SAndrew Morton 	bio = NULL;
3833a4f7577SAndrew Morton 	do_gettimeofday(&start);
3844ff277f9SJiri Slaby 	while (1) {
385d3c1b24cSJiri Slaby 		ret = snapshot_read_next(snapshot);
3864ff277f9SJiri Slaby 		if (ret <= 0)
3874ff277f9SJiri Slaby 			break;
3884ff277f9SJiri Slaby 		ret = swap_write_page(handle, data_of(*snapshot), &bio);
3894ff277f9SJiri Slaby 		if (ret)
39061159a31SRafael J. Wysocki 			break;
39161159a31SRafael J. Wysocki 		if (!(nr_pages % m))
39266d0ae4dSJiri Slaby 			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
39361159a31SRafael J. Wysocki 		nr_pages++;
39461159a31SRafael J. Wysocki 	}
3958a0d613fSJiri Slaby 	err2 = hib_wait_on_bio_chain(&bio);
3963a4f7577SAndrew Morton 	do_gettimeofday(&stop);
3974ff277f9SJiri Slaby 	if (!ret)
3984ff277f9SJiri Slaby 		ret = err2;
3994ff277f9SJiri Slaby 	if (!ret)
40066d0ae4dSJiri Slaby 		printk(KERN_CONT "\b\b\b\bdone\n");
4014ff277f9SJiri Slaby 	else
40266d0ae4dSJiri Slaby 		printk(KERN_CONT "\n");
4030d3a9abeSRafael J. Wysocki 	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
4044ff277f9SJiri Slaby 	return ret;
40561159a31SRafael J. Wysocki }
40661159a31SRafael J. Wysocki 
40761159a31SRafael J. Wysocki /**
40861159a31SRafael J. Wysocki  *	enough_swap - Make sure we have enough swap to save the image.
40961159a31SRafael J. Wysocki  *
41061159a31SRafael J. Wysocki  *	Returns TRUE or FALSE after checking the total amount of swap
41161159a31SRafael J. Wysocki  *	space avaiable from the resume partition.
41261159a31SRafael J. Wysocki  */
41361159a31SRafael J. Wysocki 
41461159a31SRafael J. Wysocki static int enough_swap(unsigned int nr_pages)
41561159a31SRafael J. Wysocki {
41661159a31SRafael J. Wysocki 	unsigned int free_swap = count_swap_pages(root_swap, 1);
41761159a31SRafael J. Wysocki 
41823976728SRafael J. Wysocki 	pr_debug("PM: Free swap pages: %u\n", free_swap);
419940864ddSRafael J. Wysocki 	return free_swap > nr_pages + PAGES_FOR_IO;
42061159a31SRafael J. Wysocki }
42161159a31SRafael J. Wysocki 
42261159a31SRafael J. Wysocki /**
42361159a31SRafael J. Wysocki  *	swsusp_write - Write entire image and metadata.
424a634cc10SRafael J. Wysocki  *	@flags: flags to pass to the "boot" kernel in the image header
42561159a31SRafael J. Wysocki  *
42661159a31SRafael J. Wysocki  *	It is important _NOT_ to umount filesystems at this point. We want
42761159a31SRafael J. Wysocki  *	them synced (in case something goes wrong) but we DO not want to mark
42861159a31SRafael J. Wysocki  *	filesystem clean: it is not. (And it does not matter, if we resume
42961159a31SRafael J. Wysocki  *	correctly, we'll mark system clean, anyway.)
43061159a31SRafael J. Wysocki  */
43161159a31SRafael J. Wysocki 
432a634cc10SRafael J. Wysocki int swsusp_write(unsigned int flags)
43361159a31SRafael J. Wysocki {
43461159a31SRafael J. Wysocki 	struct swap_map_handle handle;
43561159a31SRafael J. Wysocki 	struct snapshot_handle snapshot;
43661159a31SRafael J. Wysocki 	struct swsusp_info *header;
4376f612af5SJiri Slaby 	unsigned long pages;
43861159a31SRafael J. Wysocki 	int error;
43961159a31SRafael J. Wysocki 
4406f612af5SJiri Slaby 	pages = snapshot_get_image_size();
4416f612af5SJiri Slaby 	error = get_swap_writer(&handle);
4423aef83e0SRafael J. Wysocki 	if (error) {
4436f612af5SJiri Slaby 		printk(KERN_ERR "PM: Cannot get swap writer\n");
44461159a31SRafael J. Wysocki 		return error;
44561159a31SRafael J. Wysocki 	}
4466f612af5SJiri Slaby 	if (!enough_swap(pages)) {
4476f612af5SJiri Slaby 		printk(KERN_ERR "PM: Not enough free swap\n");
4486f612af5SJiri Slaby 		error = -ENOSPC;
4496f612af5SJiri Slaby 		goto out_finish;
4506f612af5SJiri Slaby 	}
45161159a31SRafael J. Wysocki 	memset(&snapshot, 0, sizeof(struct snapshot_handle));
452d3c1b24cSJiri Slaby 	error = snapshot_read_next(&snapshot);
4533aef83e0SRafael J. Wysocki 	if (error < PAGE_SIZE) {
4543aef83e0SRafael J. Wysocki 		if (error >= 0)
4553aef83e0SRafael J. Wysocki 			error = -EFAULT;
4563aef83e0SRafael J. Wysocki 
4576f612af5SJiri Slaby 		goto out_finish;
4583aef83e0SRafael J. Wysocki 	}
45961159a31SRafael J. Wysocki 	header = (struct swsusp_info *)data_of(snapshot);
460ab954160SAndrew Morton 	error = swap_write_page(&handle, header, NULL);
46161159a31SRafael J. Wysocki 	if (!error)
4626f612af5SJiri Slaby 		error = save_image(&handle, &snapshot, pages - 1);
4636f612af5SJiri Slaby out_finish:
4646f612af5SJiri Slaby 	error = swap_writer_finish(&handle, flags, error);
46561159a31SRafael J. Wysocki 	return error;
46661159a31SRafael J. Wysocki }
46761159a31SRafael J. Wysocki 
46861159a31SRafael J. Wysocki /**
46961159a31SRafael J. Wysocki  *	The following functions allow us to read data using a swap map
47061159a31SRafael J. Wysocki  *	in a file-alike way
47161159a31SRafael J. Wysocki  */
47261159a31SRafael J. Wysocki 
47361159a31SRafael J. Wysocki static void release_swap_reader(struct swap_map_handle *handle)
47461159a31SRafael J. Wysocki {
47561159a31SRafael J. Wysocki 	if (handle->cur)
47661159a31SRafael J. Wysocki 		free_page((unsigned long)handle->cur);
47761159a31SRafael J. Wysocki 	handle->cur = NULL;
47861159a31SRafael J. Wysocki }
47961159a31SRafael J. Wysocki 
4806f612af5SJiri Slaby static int get_swap_reader(struct swap_map_handle *handle,
4816f612af5SJiri Slaby 		unsigned int *flags_p)
48261159a31SRafael J. Wysocki {
48361159a31SRafael J. Wysocki 	int error;
48461159a31SRafael J. Wysocki 
4856f612af5SJiri Slaby 	*flags_p = swsusp_header->flags;
4866f612af5SJiri Slaby 
4876f612af5SJiri Slaby 	if (!swsusp_header->image) /* how can this happen? */
48861159a31SRafael J. Wysocki 		return -EINVAL;
4893aef83e0SRafael J. Wysocki 
49085949121SRafael J. Wysocki 	handle->cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
49161159a31SRafael J. Wysocki 	if (!handle->cur)
49261159a31SRafael J. Wysocki 		return -ENOMEM;
4933aef83e0SRafael J. Wysocki 
4946f612af5SJiri Slaby 	error = hib_bio_read_page(swsusp_header->image, handle->cur, NULL);
49561159a31SRafael J. Wysocki 	if (error) {
49661159a31SRafael J. Wysocki 		release_swap_reader(handle);
49761159a31SRafael J. Wysocki 		return error;
49861159a31SRafael J. Wysocki 	}
49961159a31SRafael J. Wysocki 	handle->k = 0;
50061159a31SRafael J. Wysocki 	return 0;
50161159a31SRafael J. Wysocki }
50261159a31SRafael J. Wysocki 
503546e0d27SAndrew Morton static int swap_read_page(struct swap_map_handle *handle, void *buf,
504546e0d27SAndrew Morton 				struct bio **bio_chain)
50561159a31SRafael J. Wysocki {
5063aef83e0SRafael J. Wysocki 	sector_t offset;
50761159a31SRafael J. Wysocki 	int error;
50861159a31SRafael J. Wysocki 
50961159a31SRafael J. Wysocki 	if (!handle->cur)
51061159a31SRafael J. Wysocki 		return -EINVAL;
51161159a31SRafael J. Wysocki 	offset = handle->cur->entries[handle->k];
51261159a31SRafael J. Wysocki 	if (!offset)
51361159a31SRafael J. Wysocki 		return -EFAULT;
5148a0d613fSJiri Slaby 	error = hib_bio_read_page(offset, buf, bio_chain);
51561159a31SRafael J. Wysocki 	if (error)
51661159a31SRafael J. Wysocki 		return error;
51761159a31SRafael J. Wysocki 	if (++handle->k >= MAP_PAGE_ENTRIES) {
5188a0d613fSJiri Slaby 		error = hib_wait_on_bio_chain(bio_chain);
51961159a31SRafael J. Wysocki 		handle->k = 0;
52061159a31SRafael J. Wysocki 		offset = handle->cur->next_swap;
52161159a31SRafael J. Wysocki 		if (!offset)
52261159a31SRafael J. Wysocki 			release_swap_reader(handle);
523546e0d27SAndrew Morton 		else if (!error)
5248a0d613fSJiri Slaby 			error = hib_bio_read_page(offset, handle->cur, NULL);
52561159a31SRafael J. Wysocki 	}
52661159a31SRafael J. Wysocki 	return error;
52761159a31SRafael J. Wysocki }
52861159a31SRafael J. Wysocki 
5296f612af5SJiri Slaby static int swap_reader_finish(struct swap_map_handle *handle)
5306f612af5SJiri Slaby {
5316f612af5SJiri Slaby 	release_swap_reader(handle);
5326f612af5SJiri Slaby 
5336f612af5SJiri Slaby 	return 0;
5346f612af5SJiri Slaby }
5356f612af5SJiri Slaby 
53661159a31SRafael J. Wysocki /**
53761159a31SRafael J. Wysocki  *	load_image - load the image using the swap map handle
53861159a31SRafael J. Wysocki  *	@handle and the snapshot handle @snapshot
53961159a31SRafael J. Wysocki  *	(assume there are @nr_pages pages to load)
54061159a31SRafael J. Wysocki  */
54161159a31SRafael J. Wysocki 
54261159a31SRafael J. Wysocki static int load_image(struct swap_map_handle *handle,
54361159a31SRafael J. Wysocki                       struct snapshot_handle *snapshot,
544546e0d27SAndrew Morton                       unsigned int nr_to_read)
54561159a31SRafael J. Wysocki {
54661159a31SRafael J. Wysocki 	unsigned int m;
54761159a31SRafael J. Wysocki 	int error = 0;
5488c002494SAndrew Morton 	struct timeval start;
5498c002494SAndrew Morton 	struct timeval stop;
550546e0d27SAndrew Morton 	struct bio *bio;
551546e0d27SAndrew Morton 	int err2;
552546e0d27SAndrew Morton 	unsigned nr_pages;
55361159a31SRafael J. Wysocki 
55423976728SRafael J. Wysocki 	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
55523976728SRafael J. Wysocki 		nr_to_read);
556546e0d27SAndrew Morton 	m = nr_to_read / 100;
55761159a31SRafael J. Wysocki 	if (!m)
55861159a31SRafael J. Wysocki 		m = 1;
55961159a31SRafael J. Wysocki 	nr_pages = 0;
560546e0d27SAndrew Morton 	bio = NULL;
5618c002494SAndrew Morton 	do_gettimeofday(&start);
562546e0d27SAndrew Morton 	for ( ; ; ) {
563d3c1b24cSJiri Slaby 		error = snapshot_write_next(snapshot);
564546e0d27SAndrew Morton 		if (error <= 0)
565546e0d27SAndrew Morton 			break;
566546e0d27SAndrew Morton 		error = swap_read_page(handle, data_of(*snapshot), &bio);
567546e0d27SAndrew Morton 		if (error)
568546e0d27SAndrew Morton 			break;
569546e0d27SAndrew Morton 		if (snapshot->sync_read)
5708a0d613fSJiri Slaby 			error = hib_wait_on_bio_chain(&bio);
57161159a31SRafael J. Wysocki 		if (error)
57261159a31SRafael J. Wysocki 			break;
57361159a31SRafael J. Wysocki 		if (!(nr_pages % m))
57461159a31SRafael J. Wysocki 			printk("\b\b\b\b%3d%%", nr_pages / m);
57561159a31SRafael J. Wysocki 		nr_pages++;
57661159a31SRafael J. Wysocki 	}
5778a0d613fSJiri Slaby 	err2 = hib_wait_on_bio_chain(&bio);
5788c002494SAndrew Morton 	do_gettimeofday(&stop);
579546e0d27SAndrew Morton 	if (!error)
580546e0d27SAndrew Morton 		error = err2;
581e655a250SCon Kolivas 	if (!error) {
58261159a31SRafael J. Wysocki 		printk("\b\b\b\bdone\n");
5838357376dSRafael J. Wysocki 		snapshot_write_finalize(snapshot);
58461159a31SRafael J. Wysocki 		if (!snapshot_image_loaded(snapshot))
58561159a31SRafael J. Wysocki 			error = -ENODATA;
586bf9fd67aSJiri Slaby 	} else
587bf9fd67aSJiri Slaby 		printk("\n");
5880d3a9abeSRafael J. Wysocki 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
58961159a31SRafael J. Wysocki 	return error;
59061159a31SRafael J. Wysocki }
59161159a31SRafael J. Wysocki 
592a634cc10SRafael J. Wysocki /**
593a634cc10SRafael J. Wysocki  *	swsusp_read - read the hibernation image.
594a634cc10SRafael J. Wysocki  *	@flags_p: flags passed by the "frozen" kernel in the image header should
595a634cc10SRafael J. Wysocki  *		  be written into this memeory location
596a634cc10SRafael J. Wysocki  */
597a634cc10SRafael J. Wysocki 
598a634cc10SRafael J. Wysocki int swsusp_read(unsigned int *flags_p)
59961159a31SRafael J. Wysocki {
60061159a31SRafael J. Wysocki 	int error;
60161159a31SRafael J. Wysocki 	struct swap_map_handle handle;
60261159a31SRafael J. Wysocki 	struct snapshot_handle snapshot;
60361159a31SRafael J. Wysocki 	struct swsusp_info *header;
60461159a31SRafael J. Wysocki 
60561159a31SRafael J. Wysocki 	memset(&snapshot, 0, sizeof(struct snapshot_handle));
606d3c1b24cSJiri Slaby 	error = snapshot_write_next(&snapshot);
60761159a31SRafael J. Wysocki 	if (error < PAGE_SIZE)
60861159a31SRafael J. Wysocki 		return error < 0 ? error : -EFAULT;
60961159a31SRafael J. Wysocki 	header = (struct swsusp_info *)data_of(snapshot);
6106f612af5SJiri Slaby 	error = get_swap_reader(&handle, flags_p);
6116f612af5SJiri Slaby 	if (error)
6126f612af5SJiri Slaby 		goto end;
61361159a31SRafael J. Wysocki 	if (!error)
614546e0d27SAndrew Morton 		error = swap_read_page(&handle, header, NULL);
61561159a31SRafael J. Wysocki 	if (!error)
61661159a31SRafael J. Wysocki 		error = load_image(&handle, &snapshot, header->pages - 1);
6176f612af5SJiri Slaby 	swap_reader_finish(&handle);
6186f612af5SJiri Slaby end:
61961159a31SRafael J. Wysocki 	if (!error)
62023976728SRafael J. Wysocki 		pr_debug("PM: Image successfully loaded\n");
62161159a31SRafael J. Wysocki 	else
62223976728SRafael J. Wysocki 		pr_debug("PM: Error %d resuming\n", error);
62361159a31SRafael J. Wysocki 	return error;
62461159a31SRafael J. Wysocki }
62561159a31SRafael J. Wysocki 
62661159a31SRafael J. Wysocki /**
62761159a31SRafael J. Wysocki  *      swsusp_check - Check for swsusp signature in the resume device
62861159a31SRafael J. Wysocki  */
62961159a31SRafael J. Wysocki 
63061159a31SRafael J. Wysocki int swsusp_check(void)
63161159a31SRafael J. Wysocki {
63261159a31SRafael J. Wysocki 	int error;
63361159a31SRafael J. Wysocki 
6348a0d613fSJiri Slaby 	hib_resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
6358a0d613fSJiri Slaby 	if (!IS_ERR(hib_resume_bdev)) {
6368a0d613fSJiri Slaby 		set_blocksize(hib_resume_bdev, PAGE_SIZE);
6376373da1fSOGAWA Hirofumi 		memset(swsusp_header, 0, PAGE_SIZE);
6388a0d613fSJiri Slaby 		error = hib_bio_read_page(swsusp_resume_block,
6391b29c164SVivek Goyal 					swsusp_header, NULL);
6409a154d9dSRafael J. Wysocki 		if (error)
64176b57e61SJiri Slaby 			goto put;
6429a154d9dSRafael J. Wysocki 
6431b29c164SVivek Goyal 		if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
6441b29c164SVivek Goyal 			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
64561159a31SRafael J. Wysocki 			/* Reset swap signature now */
6468a0d613fSJiri Slaby 			error = hib_bio_write_page(swsusp_resume_block,
6471b29c164SVivek Goyal 						swsusp_header, NULL);
64861159a31SRafael J. Wysocki 		} else {
64976b57e61SJiri Slaby 			error = -EINVAL;
65061159a31SRafael J. Wysocki 		}
65176b57e61SJiri Slaby 
65276b57e61SJiri Slaby put:
65361159a31SRafael J. Wysocki 		if (error)
6548a0d613fSJiri Slaby 			blkdev_put(hib_resume_bdev, FMODE_READ);
65561159a31SRafael J. Wysocki 		else
65623976728SRafael J. Wysocki 			pr_debug("PM: Signature found, resuming\n");
65761159a31SRafael J. Wysocki 	} else {
6588a0d613fSJiri Slaby 		error = PTR_ERR(hib_resume_bdev);
65961159a31SRafael J. Wysocki 	}
66061159a31SRafael J. Wysocki 
66161159a31SRafael J. Wysocki 	if (error)
66223976728SRafael J. Wysocki 		pr_debug("PM: Error %d checking image file\n", error);
66361159a31SRafael J. Wysocki 
66461159a31SRafael J. Wysocki 	return error;
66561159a31SRafael J. Wysocki }
66661159a31SRafael J. Wysocki 
66761159a31SRafael J. Wysocki /**
66861159a31SRafael J. Wysocki  *	swsusp_close - close swap device.
66961159a31SRafael J. Wysocki  */
67061159a31SRafael J. Wysocki 
671c2dd0daeSAl Viro void swsusp_close(fmode_t mode)
67261159a31SRafael J. Wysocki {
6738a0d613fSJiri Slaby 	if (IS_ERR(hib_resume_bdev)) {
67423976728SRafael J. Wysocki 		pr_debug("PM: Image device not initialised\n");
67561159a31SRafael J. Wysocki 		return;
67661159a31SRafael J. Wysocki 	}
67761159a31SRafael J. Wysocki 
6788a0d613fSJiri Slaby 	blkdev_put(hib_resume_bdev, mode);
67961159a31SRafael J. Wysocki }
6801b29c164SVivek Goyal 
6811b29c164SVivek Goyal static int swsusp_header_init(void)
6821b29c164SVivek Goyal {
6831b29c164SVivek Goyal 	swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
6841b29c164SVivek Goyal 	if (!swsusp_header)
6851b29c164SVivek Goyal 		panic("Could not allocate memory for swsusp_header\n");
6861b29c164SVivek Goyal 	return 0;
6871b29c164SVivek Goyal }
6881b29c164SVivek Goyal 
6891b29c164SVivek Goyal core_initcall(swsusp_header_init);
690