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
/*
 * 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/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 已提交
22
#include <linux/blkdev.h>
23 24 25 26 27 28 29 30
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/pm.h>

#include "power.h"

#define SWSUSP_SIG	"S1SUSPEND"

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

static struct swsusp_header *swsusp_header;
40 41

/*
42
 * General things
43 44 45
 */

static unsigned short root_swap = 0xffff;
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
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)
{
62
	const int bio_rw = rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
63 64
	struct bio *bio;

R
Rafael J. Wysocki 已提交
65
	bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
66 67 68 69 70
	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 已提交
71 72
		printk(KERN_ERR "PM: Adding page to bio failed at %ld\n",
			page_off);
73 74 75 76 77 78 79 80
		bio_put(bio);
		return -EFAULT;
	}

	lock_page(page);
	bio_get(bio);

	if (bio_chain == NULL) {
81
		submit_bio(bio_rw, bio);
82 83 84 85 86 87 88 89 90
		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;
91
		submit_bio(bio_rw, bio);
92 93 94 95 96 97 98 99 100
	}
	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);
}

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

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

138
static int mark_swapfiles(sector_t start, unsigned int flags)
139 140 141
{
	int error;

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

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

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

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

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

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

	if (!offset)
		return -ENOSPC;

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

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

228
#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
229 230

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

447
	if (!start)
448
		return -EINVAL;
449

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

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

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

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

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

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

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

A
Al Viro 已提交
575
	blkdev_put(resume_bdev, FMODE_READ);
576 577

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

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

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

	return error;
}

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

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

634
	blkdev_put(resume_bdev, mode);
635
}
636 637 638 639 640 641 642 643 644 645

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