2008-01-29 16:53:40 +03:00
/*
* Functions related to setting various queue properties from drivers
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/bio.h>
# include <linux/blkdev.h>
# include "blk.h"
/*
* for max sense size
*/
# include <scsi/scsi_cmnd.h>
/**
* blk_end_sync_rq - executes a completion event on a request
* @ rq : request to complete
2008-08-19 22:13:11 +04:00
* @ error : end I / O status of the request
2008-01-29 16:53:40 +03:00
*/
2008-07-15 23:21:45 +04:00
static void blk_end_sync_rq ( struct request * rq , int error )
2008-01-29 16:53:40 +03:00
{
struct completion * waiting = rq - > end_io_data ;
rq - > end_io_data = NULL ;
__blk_put_request ( rq - > q , rq ) ;
/*
* complete last , if this is a stack request the process ( and thus
* the rq pointer ) could be invalid right after this complete ( )
*/
complete ( waiting ) ;
}
/**
* blk_execute_rq_nowait - insert a request into queue for execution
* @ q : queue to insert the request in
* @ bd_disk : matching gendisk
* @ rq : request to insert
* @ at_head : insert request at head or tail of queue
* @ done : I / O completion handler
*
* Description :
2008-08-19 22:13:11 +04:00
* Insert a fully prepared request at the back of the I / O scheduler queue
2008-01-29 16:53:40 +03:00
* for execution . Don ' t wait for completion .
*/
void blk_execute_rq_nowait ( struct request_queue * q , struct gendisk * bd_disk ,
struct request * rq , int at_head ,
rq_end_io_fn * done )
{
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK ;
rq - > rq_disk = bd_disk ;
rq - > end_io = done ;
WARN_ON ( irqs_disabled ( ) ) ;
spin_lock_irq ( q - > queue_lock ) ;
2011-03-10 10:52:07 +03:00
__elv_add_request ( q , rq , where ) ;
2011-04-18 13:41:33 +04:00
__blk_run_queue ( q ) ;
2011-05-06 01:10:05 +04:00
/* the queue is stopped so it won't be run */
2010-08-07 20:17:56 +04:00
if ( rq - > cmd_type = = REQ_TYPE_PM_RESUME )
2008-07-15 23:21:43 +04:00
q - > request_fn ( q ) ;
2008-01-29 16:53:40 +03:00
spin_unlock_irq ( q - > queue_lock ) ;
}
EXPORT_SYMBOL_GPL ( blk_execute_rq_nowait ) ;
/**
* blk_execute_rq - insert a request into queue for execution
* @ q : queue to insert the request in
* @ bd_disk : matching gendisk
* @ rq : request to insert
* @ at_head : insert request at head or tail of queue
*
* Description :
2008-08-19 22:13:11 +04:00
* Insert a fully prepared request at the back of the I / O scheduler queue
2008-01-29 16:53:40 +03:00
* for execution and wait for completion .
*/
int blk_execute_rq ( struct request_queue * q , struct gendisk * bd_disk ,
struct request * rq , int at_head )
{
DECLARE_COMPLETION_ONSTACK ( wait ) ;
char sense [ SCSI_SENSE_BUFFERSIZE ] ;
int err = 0 ;
2010-09-24 17:51:13 +04:00
unsigned long hang_check ;
2008-01-29 16:53:40 +03:00
/*
* we need an extra reference to the request , so we can look at
* it after io completion
*/
rq - > ref_count + + ;
if ( ! rq - > sense ) {
memset ( sense , 0 , sizeof ( sense ) ) ;
rq - > sense = sense ;
rq - > sense_len = 0 ;
}
rq - > end_io_data = & wait ;
blk_execute_rq_nowait ( q , bd_disk , rq , at_head , blk_end_sync_rq ) ;
2010-09-24 17:51:13 +04:00
/* Prevent hang_check timer from firing at us during very long I/O */
hang_check = sysctl_hung_task_timeout_secs ;
if ( hang_check )
while ( ! wait_for_completion_timeout ( & wait , hang_check * ( HZ / 2 ) ) ) ;
else
wait_for_completion ( & wait ) ;
2008-01-29 16:53:40 +03:00
if ( rq - > errors )
err = - EIO ;
return err ;
}
EXPORT_SYMBOL ( blk_execute_rq ) ;