2008-01-29 21:51:59 +08:00
|
|
|
#ifndef BLK_INTERNAL_H
|
|
|
|
#define BLK_INTERNAL_H
|
|
|
|
|
2008-01-29 21:53:40 +08:00
|
|
|
/* Amount of time in which a process may batch requests */
|
|
|
|
#define BLK_BATCH_TIME (HZ/50UL)
|
|
|
|
|
|
|
|
/* Number of requests a "batching" process may submit */
|
|
|
|
#define BLK_BATCH_REQ 32
|
|
|
|
|
2008-01-29 21:51:59 +08:00
|
|
|
extern struct kmem_cache *blk_requestq_cachep;
|
|
|
|
extern struct kobj_type blk_queue_ktype;
|
|
|
|
|
2008-01-29 21:53:40 +08:00
|
|
|
void init_request_from_bio(struct request *req, struct bio *bio);
|
|
|
|
void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
|
|
|
|
struct bio *bio);
|
2009-05-18 00:00:01 +08:00
|
|
|
int blk_rq_append_bio(struct request_queue *q, struct request *rq,
|
|
|
|
struct bio *bio);
|
2009-05-08 10:54:16 +08:00
|
|
|
void blk_dequeue_request(struct request *rq);
|
2008-01-29 21:51:59 +08:00
|
|
|
void __blk_queue_free_tags(struct request_queue *q);
|
|
|
|
|
2008-09-14 20:55:09 +08:00
|
|
|
void blk_rq_timed_out_timer(unsigned long data);
|
|
|
|
void blk_delete_timer(struct request *);
|
|
|
|
void blk_add_timer(struct request *);
|
2008-10-17 20:03:08 +08:00
|
|
|
void __generic_unplug_device(struct request_queue *);
|
2008-09-14 20:55:09 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Internal atomic flags for request handling
|
|
|
|
*/
|
|
|
|
enum rq_atomic_flags {
|
|
|
|
REQ_ATOM_COMPLETE = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EH timer and IO completion will both attempt to 'grab' the request, make
|
2011-03-31 09:57:33 +08:00
|
|
|
* sure that only one of them succeeds
|
2008-09-14 20:55:09 +08:00
|
|
|
*/
|
|
|
|
static inline int blk_mark_rq_complete(struct request *rq)
|
|
|
|
{
|
|
|
|
return test_and_set_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void blk_clear_rq_complete(struct request *rq)
|
|
|
|
{
|
|
|
|
clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
|
|
|
|
}
|
2008-01-29 21:53:40 +08:00
|
|
|
|
2009-04-23 10:05:18 +08:00
|
|
|
/*
|
|
|
|
* Internal elevator interface
|
|
|
|
*/
|
|
|
|
#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash))
|
|
|
|
|
2011-01-25 19:43:54 +08:00
|
|
|
void blk_insert_flush(struct request *rq);
|
|
|
|
void blk_abort_flushes(struct request_queue *q);
|
2010-09-03 17:56:16 +08:00
|
|
|
|
2009-04-23 10:05:18 +08:00
|
|
|
static inline struct request *__elv_next_request(struct request_queue *q)
|
|
|
|
{
|
|
|
|
struct request *rq;
|
|
|
|
|
|
|
|
while (1) {
|
2011-01-25 19:43:54 +08:00
|
|
|
if (!list_empty(&q->queue_head)) {
|
2009-04-23 10:05:18 +08:00
|
|
|
rq = list_entry_rq(q->queue_head.next);
|
2011-01-25 19:43:54 +08:00
|
|
|
return rq;
|
2009-04-23 10:05:18 +08:00
|
|
|
}
|
|
|
|
|
block: hold queue if flush is running for non-queueable flush drive
In some drives, flush requests are non-queueable. When flush request is
running, normal read/write requests can't run. If block layer dispatches
such request, driver can't handle it and requeue it. Tejun suggested we
can hold the queue when flush is running. This can avoid unnecessary
requeue. Also this can improve performance. For example, we have
request flush1, write1, flush 2. flush1 is dispatched, then queue is
hold, write1 isn't inserted to queue. After flush1 is finished, flush2
will be dispatched. Since disk cache is already clean, flush2 will be
finished very soon, so looks like flush2 is folded to flush1.
In my test, the queue holding completely solves a regression introduced by
commit 53d63e6b0dfb95882ec0219ba6bbd50cde423794:
block: make the flush insertion use the tail of the dispatch list
It's not a preempt type request, in fact we have to insert it
behind requests that do specify INSERT_FRONT.
which causes about 20% regression running a sysbench fileio
workload.
Stable: 2.6.39 only
Cc: stable@kernel.org
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
2011-05-07 01:34:41 +08:00
|
|
|
/*
|
|
|
|
* Flush request is running and flush request isn't queueable
|
|
|
|
* in the drive, we can hold the queue till flush request is
|
|
|
|
* finished. Even we don't do this, driver can't dispatch next
|
|
|
|
* requests and will requeue them. And this can improve
|
|
|
|
* throughput too. For example, we have request flush1, write1,
|
|
|
|
* flush 2. flush1 is dispatched, then queue is hold, write1
|
|
|
|
* isn't inserted to queue. After flush1 is finished, flush2
|
|
|
|
* will be dispatched. Since disk cache is already clean,
|
|
|
|
* flush2 will be finished very soon, so looks like flush2 is
|
|
|
|
* folded to flush1.
|
|
|
|
* Since the queue is hold, a flag is set to indicate the queue
|
|
|
|
* should be restarted later. Please see flush_end_io() for
|
|
|
|
* details.
|
|
|
|
*/
|
|
|
|
if (q->flush_pending_idx != q->flush_running_idx &&
|
|
|
|
!queue_flush_queueable(q)) {
|
|
|
|
q->flush_queue_delayed = 1;
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-05-18 22:20:10 +08:00
|
|
|
if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags) ||
|
|
|
|
!q->elevator->ops->elevator_dispatch_fn(q, 0))
|
2009-04-23 10:05:18 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void elv_activate_rq(struct request_queue *q, struct request *rq)
|
|
|
|
{
|
|
|
|
struct elevator_queue *e = q->elevator;
|
|
|
|
|
|
|
|
if (e->ops->elevator_activate_req_fn)
|
|
|
|
e->ops->elevator_activate_req_fn(q, rq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq)
|
|
|
|
{
|
|
|
|
struct elevator_queue *e = q->elevator;
|
|
|
|
|
|
|
|
if (e->ops->elevator_deactivate_req_fn)
|
|
|
|
e->ops->elevator_deactivate_req_fn(q, rq);
|
|
|
|
}
|
|
|
|
|
2008-09-14 20:56:33 +08:00
|
|
|
#ifdef CONFIG_FAIL_IO_TIMEOUT
|
|
|
|
int blk_should_fake_timeout(struct request_queue *);
|
|
|
|
ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
|
|
|
|
ssize_t part_timeout_store(struct device *, struct device_attribute *,
|
|
|
|
const char *, size_t);
|
|
|
|
#else
|
|
|
|
static inline int blk_should_fake_timeout(struct request_queue *q)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-01-29 21:53:40 +08:00
|
|
|
struct io_context *current_io_context(gfp_t gfp_flags, int node);
|
|
|
|
|
2008-01-29 21:04:06 +08:00
|
|
|
int ll_back_merge_fn(struct request_queue *q, struct request *req,
|
|
|
|
struct bio *bio);
|
|
|
|
int ll_front_merge_fn(struct request_queue *q, struct request *req,
|
|
|
|
struct bio *bio);
|
|
|
|
int attempt_back_merge(struct request_queue *q, struct request *rq);
|
|
|
|
int attempt_front_merge(struct request_queue *q, struct request *rq);
|
2011-03-21 17:14:27 +08:00
|
|
|
int blk_attempt_req_merge(struct request_queue *q, struct request *rq,
|
|
|
|
struct request *next);
|
2008-01-29 21:04:06 +08:00
|
|
|
void blk_recalc_rq_segments(struct request *rq);
|
2009-07-03 16:48:17 +08:00
|
|
|
void blk_rq_set_mixed_merge(struct request *rq);
|
2008-01-29 21:04:06 +08:00
|
|
|
|
2008-01-29 21:51:59 +08:00
|
|
|
void blk_queue_congestion_threshold(struct request_queue *q);
|
|
|
|
|
2008-03-04 18:23:45 +08:00
|
|
|
int blk_dev_init(void);
|
|
|
|
|
2010-10-25 04:06:02 +08:00
|
|
|
void elv_quiesce_start(struct request_queue *q);
|
|
|
|
void elv_quiesce_end(struct request_queue *q);
|
|
|
|
|
|
|
|
|
2008-01-29 21:51:59 +08:00
|
|
|
/*
|
|
|
|
* Return the threshold (number of used requests) at which the queue is
|
|
|
|
* considered to be congested. It include a little hysteresis to keep the
|
|
|
|
* context switch rate down.
|
|
|
|
*/
|
|
|
|
static inline int queue_congestion_on_threshold(struct request_queue *q)
|
|
|
|
{
|
|
|
|
return q->nr_congestion_on;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The threshold at which a queue is considered to be uncongested
|
|
|
|
*/
|
|
|
|
static inline int queue_congestion_off_threshold(struct request_queue *q)
|
|
|
|
{
|
|
|
|
return q->nr_congestion_off;
|
|
|
|
}
|
|
|
|
|
2008-09-14 02:26:01 +08:00
|
|
|
static inline int blk_cpu_to_group(int cpu)
|
|
|
|
{
|
2010-09-10 15:03:21 +08:00
|
|
|
int group = NR_CPUS;
|
2008-09-14 02:26:01 +08:00
|
|
|
#ifdef CONFIG_SCHED_MC
|
2008-12-26 19:53:43 +08:00
|
|
|
const struct cpumask *mask = cpu_coregroup_mask(cpu);
|
2010-09-10 15:03:21 +08:00
|
|
|
group = cpumask_first(mask);
|
2008-09-14 02:26:01 +08:00
|
|
|
#elif defined(CONFIG_SCHED_SMT)
|
2010-09-10 15:03:21 +08:00
|
|
|
group = cpumask_first(topology_thread_cpumask(cpu));
|
2008-09-14 02:26:01 +08:00
|
|
|
#else
|
|
|
|
return cpu;
|
|
|
|
#endif
|
2010-09-10 15:03:21 +08:00
|
|
|
if (likely(group < NR_CPUS))
|
|
|
|
return group;
|
|
|
|
return cpu;
|
2008-09-14 02:26:01 +08:00
|
|
|
}
|
|
|
|
|
2009-04-24 14:10:11 +08:00
|
|
|
/*
|
|
|
|
* Contribute to IO statistics IFF:
|
|
|
|
*
|
|
|
|
* a) it's attached to a gendisk, and
|
|
|
|
* b) the queue had IO stats enabled when this request was started, and
|
2009-05-27 20:50:02 +08:00
|
|
|
* c) it's a file system request or a discard request
|
2009-04-24 14:10:11 +08:00
|
|
|
*/
|
2009-03-27 17:31:51 +08:00
|
|
|
static inline int blk_do_io_stat(struct request *rq)
|
2009-02-02 15:42:32 +08:00
|
|
|
{
|
2010-08-08 00:17:56 +08:00
|
|
|
return rq->rq_disk &&
|
|
|
|
(rq->cmd_flags & REQ_IO_STAT) &&
|
|
|
|
(rq->cmd_type == REQ_TYPE_FS ||
|
|
|
|
(rq->cmd_flags & REQ_DISCARD));
|
2009-02-02 15:42:32 +08:00
|
|
|
}
|
|
|
|
|
2008-01-29 21:51:59 +08:00
|
|
|
#endif
|