swap.c 14.6 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 63 64
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)
{
	struct bio *bio;

R
Rafael J. Wysocki 已提交
65
	bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
66 67 68 69 70 71 72
	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 已提交
73 74
		printk(KERN_ERR "PM: Adding page to bio failed at %ld\n",
			page_off);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
		bio_put(bio);
		return -EFAULT;
	}

	lock_page(page);
	bio_get(bio);

	if (bio_chain == NULL) {
		submit_bio(rw | (1 << BIO_RW_SYNC), bio);
		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;
		submit_bio(rw | (1 << BIO_RW_SYNC), bio);
	}
	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);
}

103
static int bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
104
{
105
	return submit(WRITE, page_off, virt_to_page(addr), bio_chain);
106 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
}

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
 */
139

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

144 145 146 147 148 149
	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;
150
		swsusp_header->flags = flags;
151
		error = bio_write_page(swsusp_resume_block,
152
					swsusp_header, NULL);
153
	} else {
R
Rafael J. Wysocki 已提交
154
		printk(KERN_ERR "PM: Swap header not found!\n");
155 156 157 158 159 160 161 162 163 164 165 166
		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 */
{
167 168
	int res;

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

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

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

	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 已提交
190
 *	@bio_chain:	Link the next write BIO here
191 192
 */

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

	if (!offset)
		return -ENOSPC;

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

/*
 *	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.
 */

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

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

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

struct swap_map_handle {
	struct swap_map_page *cur;
244
	sector_t cur_swap;
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
	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;
260
	handle->cur_swap = alloc_swapdev_block(root_swap);
261 262 263 264 265 266 267 268
	if (!handle->cur_swap) {
		release_swap_writer(handle);
		return -ENOSPC;
	}
	handle->k = 0;
	return 0;
}

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

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

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

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

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

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

/**
 *	swsusp_write - Write entire image and metadata.
373
 *	@flags: flags to pass to the "boot" kernel in the image header
374 375 376 377 378 379 380
 *
 *	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.)
 */

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

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

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

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

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

427
	release_swap_writer(&handle);
R
Rafael J. Wysocki 已提交
428
 out:
429
	swsusp_close(FMODE_WRITE);
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
	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;
}

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

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

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

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

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

	if (!handle->cur)
		return -EINVAL;
	offset = handle->cur->entries[handle->k];
	if (!offset)
		return -EFAULT;
A
Andrew Morton 已提交
476
	error = bio_read_page(offset, buf, bio_chain);
477 478 479
	if (error)
		return error;
	if (++handle->k >= MAP_PAGE_ENTRIES) {
A
Andrew Morton 已提交
480
		error = wait_on_bio_chain(bio_chain);
481 482 483 484
		handle->k = 0;
		offset = handle->cur->next_swap;
		if (!offset)
			release_swap_reader(handle);
A
Andrew Morton 已提交
485 486
		else if (!error)
			error = bio_read_page(offset, handle->cur, NULL);
487 488 489 490 491 492 493 494 495 496 497 498
	}
	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 已提交
499
                      unsigned int nr_to_read)
500 501 502
{
	unsigned int m;
	int error = 0;
503 504
	struct timeval start;
	struct timeval stop;
A
Andrew Morton 已提交
505 506 507
	struct bio *bio;
	int err2;
	unsigned nr_pages;
508

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

546 547 548 549 550 551 552
/**
 *	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)
553 554 555 556 557 558
{
	int error;
	struct swap_map_handle handle;
	struct snapshot_handle snapshot;
	struct swsusp_info *header;

559
	*flags_p = swsusp_header->flags;
560
	if (IS_ERR(resume_bdev)) {
R
Rafael J. Wysocki 已提交
561
		pr_debug("PM: Image device not initialised\n");
562 563 564 565 566 567 568 569
		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);
570
	error = get_swap_reader(&handle, swsusp_header->image);
571
	if (!error)
A
Andrew Morton 已提交
572
		error = swap_read_page(&handle, header, NULL);
573 574 575 576
	if (!error)
		error = load_image(&handle, &snapshot, header->pages - 1);
	release_swap_reader(&handle);

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

	if (!error)
R
Rafael J. Wysocki 已提交
580
		pr_debug("PM: Image successfully loaded\n");
581
	else
R
Rafael J. Wysocki 已提交
582
		pr_debug("PM: Error %d resuming\n", error);
583 584 585 586 587 588 589 590 591 592 593 594 595 596
	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);
597
		memset(swsusp_header, 0, PAGE_SIZE);
598
		error = bio_read_page(swsusp_resume_block,
599
					swsusp_header, NULL);
600
		if (error)
601
			return error;
602

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

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

	return error;
}

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

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

636
	blkdev_put(resume_bdev, mode); /* move up */
637
}
638 639 640 641 642 643 644 645 646 647

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);