2a842acab1
Currently we use nornal Linux errno values in the block layer, and while we accept any error a few have overloaded magic meanings. This patch instead introduces a new blk_status_t value that holds block layer specific status codes and explicitly explains their meaning. Helpers to convert from and to the previous special meanings are provided for now, but I suspect we want to get rid of them in the long run - those drivers that have a errno input (e.g. networking) usually get errnos that don't know about the special block layer overloads, and similarly returning them to userspace will usually return somethings that strictly speaking isn't correct for file system operations, but that's left as an exercise for later. For now the set of errors is a very limited set that closely corresponds to the previous overloaded errno values, but there is some low hanging fruite to improve it. blk_status_t (ab)uses the sparse __bitwise annotations to allow for sparse typechecking, so that we can easily catch places passing the wrong values. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@fb.com>
111 lines
2.9 KiB
C
111 lines
2.9 KiB
C
/*
|
|
* 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 <linux/blk-mq.h>
|
|
#include <linux/sched/sysctl.h>
|
|
|
|
#include "blk.h"
|
|
#include "blk-mq-sched.h"
|
|
|
|
/**
|
|
* blk_end_sync_rq - executes a completion event on a request
|
|
* @rq: request to complete
|
|
* @error: end I/O status of the request
|
|
*/
|
|
static void blk_end_sync_rq(struct request *rq, blk_status_t error)
|
|
{
|
|
struct completion *waiting = rq->end_io_data;
|
|
|
|
rq->end_io_data = NULL;
|
|
|
|
/*
|
|
* 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:
|
|
* Insert a fully prepared request at the back of the I/O scheduler queue
|
|
* for execution. Don't wait for completion.
|
|
*
|
|
* Note:
|
|
* This function will invoke @done directly if the queue is dead.
|
|
*/
|
|
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;
|
|
|
|
WARN_ON(irqs_disabled());
|
|
WARN_ON(!blk_rq_is_passthrough(rq));
|
|
|
|
rq->rq_disk = bd_disk;
|
|
rq->end_io = done;
|
|
|
|
/*
|
|
* don't check dying flag for MQ because the request won't
|
|
* be reused after dying flag is set
|
|
*/
|
|
if (q->mq_ops) {
|
|
blk_mq_sched_insert_request(rq, at_head, true, false, false);
|
|
return;
|
|
}
|
|
|
|
spin_lock_irq(q->queue_lock);
|
|
|
|
if (unlikely(blk_queue_dying(q))) {
|
|
rq->rq_flags |= RQF_QUIET;
|
|
__blk_end_request_all(rq, BLK_STS_IOERR);
|
|
spin_unlock_irq(q->queue_lock);
|
|
return;
|
|
}
|
|
|
|
__elv_add_request(q, rq, where);
|
|
__blk_run_queue(q);
|
|
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:
|
|
* Insert a fully prepared request at the back of the I/O scheduler queue
|
|
* for execution and wait for completion.
|
|
*/
|
|
void blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
|
|
struct request *rq, int at_head)
|
|
{
|
|
DECLARE_COMPLETION_ONSTACK(wait);
|
|
unsigned long hang_check;
|
|
|
|
rq->end_io_data = &wait;
|
|
blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
|
|
|
|
/* 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_io_timeout(&wait, hang_check * (HZ/2)));
|
|
else
|
|
wait_for_completion_io(&wait);
|
|
}
|
|
EXPORT_SYMBOL(blk_execute_rq);
|