swap.c 14.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * 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@suse.cz>
 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
 *
 * This file is released under the GPLv2.
 *
 */

#include <linux/module.h>
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/genhd.h>
#include <linux/device.h>
#include <linux/buffer_head.h>
#include <linux/bio.h>
A
Andrew Morton 已提交
23
#include <linux/blkdev.h>
24 25 26 27 28 29 30 31
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/pm.h>

#include "power.h"

#define SWSUSP_SIG	"S1SUSPEND"

32
struct swsusp_header {
33
	char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
34
	sector_t image;
35
	unsigned int flags;	/* Flags to pass to the "boot" kernel */
36 37
	char	orig_sig[10];
	char	sig[10];
38 39 40
} __attribute__((packed));

static struct swsusp_header *swsusp_header;
41 42

/*
43
 * General things
44 45 46
 */

static unsigned short root_swap = 0xffff;
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
static struct block_device *resume_bdev;

/**
 *	submit - submit BIO request.
 *	@rw:	READ or WRITE.
 *	@off	physical offset of page.
 *	@page:	page we're reading or writing.
 *	@bio_chain: list of pending biod (for async reading)
 *
 *	Straight from the textbook - allocate and initialize the bio.
 *	If we're reading, make sure the page is marked as dirty.
 *	Then submit it and, if @bio_chain == NULL, wait.
 */
static int submit(int rw, pgoff_t page_off, struct page *page,
			struct bio **bio_chain)
{
63
	const int bio_rw = rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
64 65
	struct bio *bio;

R
Rafael J. Wysocki 已提交
66
	bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
67 68 69 70 71 72 73
	if (!bio)
		return -ENOMEM;
	bio->bi_sector = page_off * (PAGE_SIZE >> 9);
	bio->bi_bdev = resume_bdev;
	bio->bi_end_io = end_swap_bio_read;

	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
R
Rafael J. Wysocki 已提交
74 75
		printk(KERN_ERR "PM: Adding page to bio failed at %ld\n",
			page_off);
76 77 78 79 80 81 82 83
		bio_put(bio);
		return -EFAULT;
	}

	lock_page(page);
	bio_get(bio);

	if (bio_chain == NULL) {
84
		submit_bio(bio_rw, bio);
85 86 87 88 89 90 91 92 93
		wait_on_page_locked(page);
		if (rw == READ)
			bio_set_pages_dirty(bio);
		bio_put(bio);
	} else {
		if (rw == READ)
			get_page(page);	/* These pages are freed later */
		bio->bi_private = *bio_chain;
		*bio_chain = bio;
94
		submit_bio(bio_rw, bio);
95 96 97 98 99 100 101 102 103
	}
	return 0;
}

static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
{
	return submit(READ, page_off, virt_to_page(addr), bio_chain);
}

104
static int bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
105
{
106
	return submit(WRITE, page_off, virt_to_page(addr), bio_chain);
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
}

static int wait_on_bio_chain(struct bio **bio_chain)
{
	struct bio *bio;
	struct bio *next_bio;
	int ret = 0;

	if (bio_chain == NULL)
		return 0;

	bio = *bio_chain;
	if (bio == NULL)
		return 0;
	while (bio) {
		struct page *page;

		next_bio = bio->bi_private;
		page = bio->bi_io_vec[0].bv_page;
		wait_on_page_locked(page);
		if (!PageUptodate(page) || PageError(page))
			ret = -EIO;
		put_page(page);
		bio_put(bio);
		bio = next_bio;
	}
	*bio_chain = NULL;
	return ret;
}

/*
 * Saving part
 */
140

141
static int mark_swapfiles(sector_t start, unsigned int flags)
142 143 144
{
	int error;

145 146 147 148 149 150
	bio_read_page(swsusp_resume_block, swsusp_header, NULL);
	if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
	    !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
		swsusp_header->image = start;
151
		swsusp_header->flags = flags;
152
		error = bio_write_page(swsusp_resume_block,
153
					swsusp_header, NULL);
154
	} else {
R
Rafael J. Wysocki 已提交
155
		printk(KERN_ERR "PM: Swap header not found!\n");
156 157 158 159 160 161 162 163 164 165 166 167
		error = -ENODEV;
	}
	return error;
}

/**
 *	swsusp_swap_check - check if the resume device is a swap device
 *	and get its index (if so)
 */

static int swsusp_swap_check(void) /* This is called before saving image */
{
168 169
	int res;

170 171
	res = swap_type_of(swsusp_resume_device, swsusp_resume_block,
			&resume_bdev);
172 173 174 175
	if (res < 0)
		return res;

	root_swap = res;
176
	res = blkdev_get(resume_bdev, FMODE_WRITE);
177 178
	if (res)
		return res;
179 180 181

	res = set_blocksize(resume_bdev, PAGE_SIZE);
	if (res < 0)
A
Al Viro 已提交
182
		blkdev_put(resume_bdev, FMODE_WRITE);
183 184 185 186 187 188 189 190

	return res;
}

/**
 *	write_page - Write one page to given swap location.
 *	@buf:		Address we're writing.
 *	@offset:	Offset of the swap page we're writing to.
A
Andrew Morton 已提交
191
 *	@bio_chain:	Link the next write BIO here
192 193
 */

194
static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
195
{
196 197 198 199 200 201
	void *src;

	if (!offset)
		return -ENOSPC;

	if (bio_chain) {
R
Rafael J. Wysocki 已提交
202
		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
203 204 205 206 207 208
		if (src) {
			memcpy(src, buf, PAGE_SIZE);
		} else {
			WARN_ON_ONCE(1);
			bio_chain = NULL;	/* Go synchronous */
			src = buf;
A
Andrew Morton 已提交
209
		}
210 211
	} else {
		src = buf;
212
	}
213
	return bio_write_page(offset, src, bio_chain);
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
}

/*
 *	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_SIZE 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 also only need to use one swap_map_page structure
 *	at a time.
 */

231
#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
232 233

struct swap_map_page {
234 235
	sector_t entries[MAP_PAGE_ENTRIES];
	sector_t next_swap;
236 237 238 239 240 241 242 243 244
};

/**
 *	The swap_map_handle structure is used for handling swap in
 *	a file-alike way
 */

struct swap_map_handle {
	struct swap_map_page *cur;
245
	sector_t cur_swap;
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
	unsigned int k;
};

static void release_swap_writer(struct swap_map_handle *handle)
{
	if (handle->cur)
		free_page((unsigned long)handle->cur);
	handle->cur = NULL;
}

static int get_swap_writer(struct swap_map_handle *handle)
{
	handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
	if (!handle->cur)
		return -ENOMEM;
261
	handle->cur_swap = alloc_swapdev_block(root_swap);
262 263 264 265 266 267 268 269
	if (!handle->cur_swap) {
		release_swap_writer(handle);
		return -ENOSPC;
	}
	handle->k = 0;
	return 0;
}

A
Andrew Morton 已提交
270 271 272 273
static int swap_write_page(struct swap_map_handle *handle, void *buf,
				struct bio **bio_chain)
{
	int error = 0;
274
	sector_t offset;
275 276 277

	if (!handle->cur)
		return -EINVAL;
278
	offset = alloc_swapdev_block(root_swap);
A
Andrew Morton 已提交
279
	error = write_page(buf, offset, bio_chain);
280 281 282 283
	if (error)
		return error;
	handle->cur->entries[handle->k++] = offset;
	if (handle->k >= MAP_PAGE_ENTRIES) {
A
Andrew Morton 已提交
284 285 286
		error = wait_on_bio_chain(bio_chain);
		if (error)
			goto out;
287
		offset = alloc_swapdev_block(root_swap);
288 289 290
		if (!offset)
			return -ENOSPC;
		handle->cur->next_swap = offset;
A
Andrew Morton 已提交
291
		error = write_page(handle->cur, handle->cur_swap, NULL);
292
		if (error)
A
Andrew Morton 已提交
293
			goto out;
294 295 296 297
		memset(handle->cur, 0, PAGE_SIZE);
		handle->cur_swap = offset;
		handle->k = 0;
	}
R
Rafael J. Wysocki 已提交
298
 out:
A
Andrew Morton 已提交
299
	return error;
300 301 302 303 304
}

static int flush_swap_writer(struct swap_map_handle *handle)
{
	if (handle->cur && handle->cur_swap)
A
Andrew Morton 已提交
305
		return write_page(handle->cur, handle->cur_swap, NULL);
306 307 308 309 310 311 312 313 314 315
	else
		return -EINVAL;
}

/**
 *	save_image - save the suspend image data
 */

static int save_image(struct swap_map_handle *handle,
                      struct snapshot_handle *snapshot,
316
                      unsigned int nr_to_write)
317 318 319 320
{
	unsigned int m;
	int ret;
	int error = 0;
321
	int nr_pages;
A
Andrew Morton 已提交
322 323
	int err2;
	struct bio *bio;
324 325
	struct timeval start;
	struct timeval stop;
326

R
Rafael J. Wysocki 已提交
327 328
	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
		nr_to_write);
329
	m = nr_to_write / 100;
330 331 332
	if (!m)
		m = 1;
	nr_pages = 0;
A
Andrew Morton 已提交
333
	bio = NULL;
334
	do_gettimeofday(&start);
335 336 337
	do {
		ret = snapshot_read_next(snapshot, PAGE_SIZE);
		if (ret > 0) {
A
Andrew Morton 已提交
338 339
			error = swap_write_page(handle, data_of(*snapshot),
						&bio);
340 341 342 343 344 345 346
			if (error)
				break;
			if (!(nr_pages % m))
				printk("\b\b\b\b%3d%%", nr_pages / m);
			nr_pages++;
		}
	} while (ret > 0);
A
Andrew Morton 已提交
347
	err2 = wait_on_bio_chain(&bio);
348
	do_gettimeofday(&stop);
A
Andrew Morton 已提交
349 350
	if (!error)
		error = err2;
351 352
	if (!error)
		printk("\b\b\b\bdone\n");
353
	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
354 355 356 357 358 359 360 361 362 363 364 365 366 367
	return error;
}

/**
 *	enough_swap - Make sure we have enough swap to save the image.
 *
 *	Returns TRUE or FALSE after checking the total amount of swap
 *	space avaiable from the resume partition.
 */

static int enough_swap(unsigned int nr_pages)
{
	unsigned int free_swap = count_swap_pages(root_swap, 1);

R
Rafael J. Wysocki 已提交
368
	pr_debug("PM: Free swap pages: %u\n", free_swap);
369
	return free_swap > nr_pages + PAGES_FOR_IO;
370 371 372 373
}

/**
 *	swsusp_write - Write entire image and metadata.
374
 *	@flags: flags to pass to the "boot" kernel in the image header
375 376 377 378 379 380 381
 *
 *	It is important _NOT_ to umount filesystems at this point. We want
 *	them synced (in case something goes wrong) but we DO not want to mark
 *	filesystem clean: it is not. (And it does not matter, if we resume
 *	correctly, we'll mark system clean, anyway.)
 */

382
int swsusp_write(unsigned int flags)
383 384 385 386 387 388
{
	struct swap_map_handle handle;
	struct snapshot_handle snapshot;
	struct swsusp_info *header;
	int error;

389 390
	error = swsusp_swap_check();
	if (error) {
R
Rafael J. Wysocki 已提交
391
		printk(KERN_ERR "PM: Cannot find swap device, try "
A
Andrew Morton 已提交
392
				"swapon -a.\n");
393 394 395 396
		return error;
	}
	memset(&snapshot, 0, sizeof(struct snapshot_handle));
	error = snapshot_read_next(&snapshot, PAGE_SIZE);
397 398 399 400 401 402
	if (error < PAGE_SIZE) {
		if (error >= 0)
			error = -EFAULT;

		goto out;
	}
403 404
	header = (struct swsusp_info *)data_of(snapshot);
	if (!enough_swap(header->pages)) {
R
Rafael J. Wysocki 已提交
405
		printk(KERN_ERR "PM: Not enough free swap\n");
406 407
		error = -ENOSPC;
		goto out;
408 409 410
	}
	error = get_swap_writer(&handle);
	if (!error) {
411 412
		sector_t start = handle.cur_swap;

A
Andrew Morton 已提交
413
		error = swap_write_page(&handle, header, NULL);
A
Andrew Morton 已提交
414 415 416
		if (!error)
			error = save_image(&handle, &snapshot,
					header->pages - 1);
417

A
Andrew Morton 已提交
418 419
		if (!error) {
			flush_swap_writer(&handle);
R
Rafael J. Wysocki 已提交
420
			printk(KERN_INFO "PM: S");
421
			error = mark_swapfiles(start, flags);
A
Andrew Morton 已提交
422 423
			printk("|\n");
		}
424 425
	}
	if (error)
426 427
		free_all_swap_pages(root_swap);

428
	release_swap_writer(&handle);
R
Rafael J. Wysocki 已提交
429
 out:
430
	swsusp_close(FMODE_WRITE);
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
	return error;
}

/**
 *	The following functions allow us to read data using a swap map
 *	in a file-alike way
 */

static void release_swap_reader(struct swap_map_handle *handle)
{
	if (handle->cur)
		free_page((unsigned long)handle->cur);
	handle->cur = NULL;
}

446
static int get_swap_reader(struct swap_map_handle *handle, sector_t start)
447 448 449
{
	int error;

450
	if (!start)
451
		return -EINVAL;
452

R
Rafael J. Wysocki 已提交
453
	handle->cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
454 455
	if (!handle->cur)
		return -ENOMEM;
456 457

	error = bio_read_page(start, handle->cur, NULL);
458 459 460 461 462 463 464 465
	if (error) {
		release_swap_reader(handle);
		return error;
	}
	handle->k = 0;
	return 0;
}

A
Andrew Morton 已提交
466 467
static int swap_read_page(struct swap_map_handle *handle, void *buf,
				struct bio **bio_chain)
468
{
469
	sector_t offset;
470 471 472 473 474 475 476
	int error;

	if (!handle->cur)
		return -EINVAL;
	offset = handle->cur->entries[handle->k];
	if (!offset)
		return -EFAULT;
A
Andrew Morton 已提交
477
	error = bio_read_page(offset, buf, bio_chain);
478 479 480
	if (error)
		return error;
	if (++handle->k >= MAP_PAGE_ENTRIES) {
A
Andrew Morton 已提交
481
		error = wait_on_bio_chain(bio_chain);
482 483 484 485
		handle->k = 0;
		offset = handle->cur->next_swap;
		if (!offset)
			release_swap_reader(handle);
A
Andrew Morton 已提交
486 487
		else if (!error)
			error = bio_read_page(offset, handle->cur, NULL);
488 489 490 491 492 493 494 495 496 497 498 499
	}
	return error;
}

/**
 *	load_image - load the image using the swap map handle
 *	@handle and the snapshot handle @snapshot
 *	(assume there are @nr_pages pages to load)
 */

static int load_image(struct swap_map_handle *handle,
                      struct snapshot_handle *snapshot,
A
Andrew Morton 已提交
500
                      unsigned int nr_to_read)
501 502 503
{
	unsigned int m;
	int error = 0;
504 505
	struct timeval start;
	struct timeval stop;
A
Andrew Morton 已提交
506 507 508
	struct bio *bio;
	int err2;
	unsigned nr_pages;
509

R
Rafael J. Wysocki 已提交
510 511
	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
		nr_to_read);
A
Andrew Morton 已提交
512
	m = nr_to_read / 100;
513 514 515
	if (!m)
		m = 1;
	nr_pages = 0;
A
Andrew Morton 已提交
516
	bio = NULL;
517
	do_gettimeofday(&start);
A
Andrew Morton 已提交
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
	for ( ; ; ) {
		error = snapshot_write_next(snapshot, PAGE_SIZE);
		if (error <= 0)
			break;
		error = swap_read_page(handle, data_of(*snapshot), &bio);
		if (error)
			break;
		if (snapshot->sync_read)
			error = wait_on_bio_chain(&bio);
		if (error)
			break;
		if (!(nr_pages % m))
			printk("\b\b\b\b%3d%%", nr_pages / m);
		nr_pages++;
	}
	err2 = wait_on_bio_chain(&bio);
534
	do_gettimeofday(&stop);
A
Andrew Morton 已提交
535 536
	if (!error)
		error = err2;
537
	if (!error) {
538
		printk("\b\b\b\bdone\n");
539
		snapshot_write_finalize(snapshot);
540 541 542
		if (!snapshot_image_loaded(snapshot))
			error = -ENODATA;
	}
543
	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
544 545 546
	return error;
}

547 548 549 550 551 552 553
/**
 *	swsusp_read - read the hibernation image.
 *	@flags_p: flags passed by the "frozen" kernel in the image header should
 *		  be written into this memeory location
 */

int swsusp_read(unsigned int *flags_p)
554 555 556 557 558 559
{
	int error;
	struct swap_map_handle handle;
	struct snapshot_handle snapshot;
	struct swsusp_info *header;

560
	*flags_p = swsusp_header->flags;
561
	if (IS_ERR(resume_bdev)) {
R
Rafael J. Wysocki 已提交
562
		pr_debug("PM: Image device not initialised\n");
563 564 565 566 567 568 569 570
		return PTR_ERR(resume_bdev);
	}

	memset(&snapshot, 0, sizeof(struct snapshot_handle));
	error = snapshot_write_next(&snapshot, PAGE_SIZE);
	if (error < PAGE_SIZE)
		return error < 0 ? error : -EFAULT;
	header = (struct swsusp_info *)data_of(snapshot);
571
	error = get_swap_reader(&handle, swsusp_header->image);
572
	if (!error)
A
Andrew Morton 已提交
573
		error = swap_read_page(&handle, header, NULL);
574 575 576 577
	if (!error)
		error = load_image(&handle, &snapshot, header->pages - 1);
	release_swap_reader(&handle);

A
Al Viro 已提交
578
	blkdev_put(resume_bdev, FMODE_READ);
579 580

	if (!error)
R
Rafael J. Wysocki 已提交
581
		pr_debug("PM: Image successfully loaded\n");
582
	else
R
Rafael J. Wysocki 已提交
583
		pr_debug("PM: Error %d resuming\n", error);
584 585 586 587 588 589 590 591 592 593 594 595 596 597
	return error;
}

/**
 *      swsusp_check - Check for swsusp signature in the resume device
 */

int swsusp_check(void)
{
	int error;

	resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
	if (!IS_ERR(resume_bdev)) {
		set_blocksize(resume_bdev, PAGE_SIZE);
598
		memset(swsusp_header, 0, PAGE_SIZE);
599
		error = bio_read_page(swsusp_resume_block,
600
					swsusp_header, NULL);
601
		if (error)
602
			return error;
603

604 605
		if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
606
			/* Reset swap signature now */
607
			error = bio_write_page(swsusp_resume_block,
608
						swsusp_header, NULL);
609 610 611 612
		} else {
			return -EINVAL;
		}
		if (error)
A
Al Viro 已提交
613
			blkdev_put(resume_bdev, FMODE_READ);
614
		else
R
Rafael J. Wysocki 已提交
615
			pr_debug("PM: Signature found, resuming\n");
616 617 618 619 620
	} else {
		error = PTR_ERR(resume_bdev);
	}

	if (error)
R
Rafael J. Wysocki 已提交
621
		pr_debug("PM: Error %d checking image file\n", error);
622 623 624 625 626 627 628 629

	return error;
}

/**
 *	swsusp_close - close swap device.
 */

630
void swsusp_close(fmode_t mode)
631 632
{
	if (IS_ERR(resume_bdev)) {
R
Rafael J. Wysocki 已提交
633
		pr_debug("PM: Image device not initialised\n");
634 635 636
		return;
	}

637
	blkdev_put(resume_bdev, mode);
638
}
639 640 641 642 643 644 645 646 647 648

static int swsusp_header_init(void)
{
	swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
	if (!swsusp_header)
		panic("Could not allocate memory for swsusp_header\n");
	return 0;
}

core_initcall(swsusp_header_init);