2010-05-02 01:52:34 +04:00
/*
* 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 ) {
2010-05-04 02:03:26 +04:00
printk ( KERN_ERR " PM: Adding page to bio failed at %llu \n " ,
( unsigned long long ) sector ) ;
2010-05-02 01:52:34 +04:00
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 ;
}