diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-20 09:03:55 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-20 09:03:55 -0700 |
commit | 46ee9645094ad1eb5b4888882ecaa1fb87dcd2a3 (patch) | |
tree | d0a48e993568b6a2415cfc21fc06eaa2fd886429 /kernel/power/block_io.c | |
parent | fa5312d9e87e7222c6c384c4e930dc149bc1178d (diff) | |
parent | 25f3a5a2854dce8b8413fd24cc9d5b9e3632be54 (diff) | |
download | linux-46ee9645094ad1eb5b4888882ecaa1fb87dcd2a3.tar.gz linux-46ee9645094ad1eb5b4888882ecaa1fb87dcd2a3.tar.bz2 linux-46ee9645094ad1eb5b4888882ecaa1fb87dcd2a3.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
PM: PM QOS update fix
Freezer / cgroup freezer: Update stale locking comments
PM / platform_bus: Allow runtime PM by default
i2c: Fix bus-level power management callbacks
PM QOS update
PM / Hibernate: Fix block_io.c printk warning
PM / Hibernate: Group swap ops
PM / Hibernate: Move the first_sector out of swsusp_write
PM / Hibernate: Separate block_io
PM / Hibernate: Snapshot cleanup
FS / libfs: Implement simple_write_to_buffer
PM / Hibernate: document open(/dev/snapshot) side effects
PM / Runtime: Add sysfs debug files
PM: Improve device power management document
PM: Update device power management document
PM: Allow runtime_suspend methods to call pm_schedule_suspend()
PM: pm_wakeup - switch to using bool
Diffstat (limited to 'kernel/power/block_io.c')
-rw-r--r-- | kernel/power/block_io.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c new file mode 100644 index 000000000000..97024fd40cd5 --- /dev/null +++ b/kernel/power/block_io.c @@ -0,0 +1,103 @@ +/* + * This file provides functions for block I/O operations on swap/file. + * + * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> + * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> + * + * This file is released under the GPLv2. + */ + +#include <linux/bio.h> +#include <linux/kernel.h> +#include <linux/pagemap.h> +#include <linux/swap.h> + +#include "power.h" + +/** + * 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, struct block_device *bdev, sector_t sector, + struct page *page, struct bio **bio_chain) +{ + const int bio_rw = rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); + struct bio *bio; + + bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); + bio->bi_sector = sector; + bio->bi_bdev = bdev; + bio->bi_end_io = end_swap_bio_read; + + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { + printk(KERN_ERR "PM: Adding page to bio failed at %llu\n", + (unsigned long long)sector); + bio_put(bio); + return -EFAULT; + } + + lock_page(page); + bio_get(bio); + + if (bio_chain == NULL) { + submit_bio(bio_rw, 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(bio_rw, bio); + } + return 0; +} + +int hib_bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain) +{ + return submit(READ, hib_resume_bdev, page_off * (PAGE_SIZE >> 9), + virt_to_page(addr), bio_chain); +} + +int hib_bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain) +{ + return submit(WRITE, hib_resume_bdev, page_off * (PAGE_SIZE >> 9), + virt_to_page(addr), bio_chain); +} + +int hib_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; +} |