mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 16:11:38 +00:00
721a9602e6
With the plugging now being explicitly controlled by the submitter, callers need not pass down unplugging hints to the block layer. If they want to unplug, it's because they manually plugged on their own - in which case, they should just unplug at will. Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
104 lines
2.4 KiB
C
104 lines
2.4 KiB
C
/*
|
|
* 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 | REQ_SYNC;
|
|
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;
|
|
}
|