Newer
Older
cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
}
static inline int
cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
const int base_rq = cfqd->cfq_slice_async_rq;
WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
/*
* get next queue for service
*/
static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
unsigned long now = jiffies;
cfqq = cfqd->active_queue;
if (!cfqq)
goto new_queue;
/*
* slice has expired
*/
if (!cfq_cfqq_must_dispatch(cfqq) && time_after(now, cfqq->slice_end))
goto expire;
/*
* if queue has requests, dispatch one. if not, check if
* enough slice is left to wait for one
*/
if (!RB_EMPTY(&cfqq->sort_list))
goto keep_queue;
else if (cfq_cfqq_class_sync(cfqq) &&
time_before(now, cfqq->slice_end)) {
if (cfq_arm_slice_timer(cfqd, cfqq))
return NULL;
}
cfq_slice_expired(cfqd, 0);
new_queue:
cfqq = cfq_set_active_queue(cfqd);
}
static int
__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
int max_dispatch)
{
int dispatched = 0;
BUG_ON(RB_EMPTY(&cfqq->sort_list));
do {
struct cfq_rq *crq;
* follow expired path, else get first next available
if ((crq = cfq_check_fifo(cfqq)) == NULL)
crq = cfqq->next_crq;
/*
* finally, insert request into driver dispatch list
*/
cfq_dispatch_insert(cfqd->queue, crq);
cfqd->dispatch_slice++;
dispatched++;
if (!cfqd->active_cic) {
atomic_inc(&crq->io_context->ioc->refcount);
cfqd->active_cic = crq->io_context;
}
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
if (RB_EMPTY(&cfqq->sort_list))
break;
} while (dispatched < max_dispatch);
/*
* if slice end isn't set yet, set it. if at least one request was
* sync, use the sync time slice value
*/
if (!cfqq->slice_end)
cfq_set_prio_slice(cfqd, cfqq);
/*
* expire an async queue immediately if it has used up its slice. idle
* queue always expire after 1 dispatch round.
*/
if ((!cfq_cfqq_sync(cfqq) &&
cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
cfq_class_idle(cfqq))
cfq_slice_expired(cfqd, 0);
return dispatched;
}
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
static int
cfq_forced_dispatch_cfqqs(struct list_head *list)
{
int dispatched = 0;
struct cfq_queue *cfqq, *next;
struct cfq_rq *crq;
list_for_each_entry_safe(cfqq, next, list, cfq_list) {
while ((crq = cfqq->next_crq)) {
cfq_dispatch_insert(cfqq->cfqd->queue, crq);
dispatched++;
}
BUG_ON(!list_empty(&cfqq->fifo));
}
return dispatched;
}
static int
cfq_forced_dispatch(struct cfq_data *cfqd)
{
int i, dispatched = 0;
for (i = 0; i < CFQ_PRIO_LISTS; i++)
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]);
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr);
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr);
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr);
cfq_slice_expired(cfqd, 0);
BUG_ON(cfqd->busy_queues);
return dispatched;
}
cfq_dispatch_requests(request_queue_t *q, int force)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_queue *cfqq;
if (!cfqd->busy_queues)
return 0;
if (unlikely(force))
return cfq_forced_dispatch(cfqd);
cfqq = cfq_select_queue(cfqd);
int max_dispatch;
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
del_timer(&cfqd->idle_slice_timer);
max_dispatch = cfqd->cfq_quantum;
if (cfq_class_idle(cfqq))
max_dispatch = 1;
return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
}
/*
* task holds one reference to the queue, dropped when task exits. each crq
* in-flight on this queue also holds a reference, dropped when crq is freed.
*
* queue lock must be held here.
*/
static void cfq_put_queue(struct cfq_queue *cfqq)
{
struct cfq_data *cfqd = cfqq->cfqd;
BUG_ON(atomic_read(&cfqq->ref) <= 0);
if (!atomic_dec_and_test(&cfqq->ref))
return;
BUG_ON(rb_first(&cfqq->sort_list));
BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
if (unlikely(cfqd->active_queue == cfqq))
/*
* it's on the empty list and still hashed
*/
list_del(&cfqq->cfq_list);
hlist_del(&cfqq->cfq_hash);
kmem_cache_free(cfq_pool, cfqq);
}
static inline struct cfq_queue *
__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
const int hashval)
{
struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
struct hlist_node *entry;
struct cfq_queue *__cfqq;
hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio);
if (__cfqq->key == key && (__p == prio || !prio))
return __cfqq;
}
return NULL;
}
static struct cfq_queue *
cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
static void cfq_free_io_context(struct io_context *ioc)
struct cfq_io_context *__cic;
struct rb_node *n;
int freed = 0;
while ((n = rb_first(&ioc->cic_root)) != NULL) {
__cic = rb_entry(n, struct cfq_io_context, rb_node);
rb_erase(&__cic->rb_node, &ioc->cic_root);
kmem_cache_free(cfq_ioc_pool, __cic);
if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone)
complete(ioc_gone);
static void cfq_trim(struct io_context *ioc)
{
ioc->set_ioprio = NULL;
cfq_free_io_context(ioc);
}
/*
* Called with interrupts disabled
*/
static void cfq_exit_single_io_context(struct cfq_io_context *cic)
struct cfq_data *cfqd = cic->key;
request_queue_t *q;
if (!cfqd)
return;
q = cfqd->queue;
WARN_ON(!irqs_disabled());
spin_lock(q->queue_lock);
if (cic->cfqq[ASYNC]) {
if (unlikely(cic->cfqq[ASYNC] == cfqd->active_queue))
__cfq_slice_expired(cfqd, cic->cfqq[ASYNC], 0);
cfq_put_queue(cic->cfqq[ASYNC]);
cic->cfqq[ASYNC] = NULL;
}
if (cic->cfqq[SYNC]) {
if (unlikely(cic->cfqq[SYNC] == cfqd->active_queue))
__cfq_slice_expired(cfqd, cic->cfqq[SYNC], 0);
cfq_put_queue(cic->cfqq[SYNC]);
cic->cfqq[SYNC] = NULL;
}
cic->key = NULL;
list_del_init(&cic->queue_list);
spin_unlock(q->queue_lock);
static void cfq_exit_io_context(struct io_context *ioc)
struct cfq_io_context *__cic;
struct rb_node *n;
/*
* put the reference this task is holding to the various queues
*/
spin_lock_irqsave(&cfq_exit_lock, flags);
n = rb_first(&ioc->cic_root);
while (n != NULL) {
__cic = rb_entry(n, struct cfq_io_context, rb_node);
cfq_exit_single_io_context(__cic);
n = rb_next(n);
spin_unlock_irqrestore(&cfq_exit_lock, flags);
static struct cfq_io_context *
cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
cic->last_end_request = jiffies;
INIT_LIST_HEAD(&cic->queue_list);
cic->dtor = cfq_free_io_context;
cic->exit = cfq_exit_io_context;
static void cfq_init_prio_data(struct cfq_queue *cfqq)
{
struct task_struct *tsk = current;
int ioprio_class;
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
return;
ioprio_class = IOPRIO_PRIO_CLASS(tsk->ioprio);
switch (ioprio_class) {
default:
printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
case IOPRIO_CLASS_NONE:
/*
* no prio set, place us in the middle of the BE classes
*/
cfqq->ioprio = task_nice_ioprio(tsk);
cfqq->ioprio_class = IOPRIO_CLASS_BE;
break;
case IOPRIO_CLASS_RT:
cfqq->ioprio = task_ioprio(tsk);
cfqq->ioprio_class = IOPRIO_CLASS_RT;
break;
case IOPRIO_CLASS_BE:
cfqq->ioprio = task_ioprio(tsk);
cfqq->ioprio_class = IOPRIO_CLASS_BE;
break;
case IOPRIO_CLASS_IDLE:
cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
cfqq->ioprio = 7;
break;
}
/*
* keep track of original prio settings in case we have to temporarily
* elevate the priority of this queue
*/
cfqq->org_ioprio = cfqq->ioprio;
cfqq->org_ioprio_class = cfqq->ioprio_class;
cfq_resort_rr_list(cfqq, 0);
static inline void changed_ioprio(struct cfq_io_context *cic)
struct cfq_data *cfqd = cic->key;
struct cfq_queue *cfqq;
if (cfqd) {
spin_lock(cfqd->queue->queue_lock);
cfqq = cic->cfqq[ASYNC];
if (cfqq) {
struct cfq_queue *new_cfqq;
new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC,
cic->ioc->task, GFP_ATOMIC);
if (new_cfqq) {
cic->cfqq[ASYNC] = new_cfqq;
cfq_put_queue(cfqq);
}
}
cfqq = cic->cfqq[SYNC];
if (cfqq) {
cfq_mark_cfqq_prio_changed(cfqq);
cfq_init_prio_data(cfqq);
}
spin_unlock(cfqd->queue->queue_lock);
}
}
/*
* callback from sys_ioprio_set, irqs are disabled
*/
static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
{
struct rb_node *n;
spin_lock(&cfq_exit_lock);
n = rb_first(&ioc->cic_root);
while (n != NULL) {
cic = rb_entry(n, struct cfq_io_context, rb_node);
changed_ioprio(cic);
n = rb_next(n);
}
spin_unlock(&cfq_exit_lock);
return 0;
}
static struct cfq_queue *
cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk,
{
const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
struct cfq_queue *cfqq, *new_cfqq = NULL;
cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
if (!cfqq) {
if (new_cfqq) {
cfqq = new_cfqq;
new_cfqq = NULL;
} else if (gfp_mask & __GFP_WAIT) {
spin_unlock_irq(cfqd->queue->queue_lock);
new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
spin_lock_irq(cfqd->queue->queue_lock);
goto retry;
} else {
cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
if (!cfqq)
goto out;
}
memset(cfqq, 0, sizeof(*cfqq));
INIT_HLIST_NODE(&cfqq->cfq_hash);
INIT_LIST_HEAD(&cfqq->cfq_list);
RB_CLEAR_ROOT(&cfqq->sort_list);
INIT_LIST_HEAD(&cfqq->fifo);
cfqq->key = key;
hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
atomic_set(&cfqq->ref, 0);
cfqq->cfqd = cfqd;
cfqq->service_last = 0;
/*
* set ->slice_left to allow preemption for a new process
*/
cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
if (!cfqd->hw_tag)
cfq_mark_cfqq_idle_window(cfqq);
cfq_mark_cfqq_prio_changed(cfqq);
cfq_init_prio_data(cfqq);
}
if (new_cfqq)
kmem_cache_free(cfq_pool, new_cfqq);
atomic_inc(&cfqq->ref);
out:
WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
return cfqq;
}
static void
cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
{
spin_lock(&cfq_exit_lock);
rb_erase(&cic->rb_node, &ioc->cic_root);
list_del_init(&cic->queue_list);
spin_unlock(&cfq_exit_lock);
kmem_cache_free(cfq_ioc_pool, cic);
atomic_dec(&ioc_count);
}
static struct cfq_io_context *
cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
{
struct cfq_io_context *cic;
void *k, *key = cfqd;
restart:
n = ioc->cic_root.rb_node;
while (n) {
cic = rb_entry(n, struct cfq_io_context, rb_node);
/* ->key must be copied to avoid race with cfq_exit_queue() */
k = cic->key;
if (unlikely(!k)) {
cfq_drop_dead_cic(ioc, cic);
goto restart;
}
if (key < k)
n = n->rb_left;
else if (key > k)
n = n->rb_right;
else
return cic;
}
return NULL;
}
static inline void
cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
struct cfq_io_context *cic)
{
struct rb_node **p;
struct rb_node *parent;
struct cfq_io_context *__cic;
void *k;
cic->ioc = ioc;
cic->key = cfqd;
ioc->set_ioprio = cfq_ioc_set_ioprio;
restart:
parent = NULL;
p = &ioc->cic_root.rb_node;
while (*p) {
parent = *p;
__cic = rb_entry(parent, struct cfq_io_context, rb_node);
/* ->key must be copied to avoid race with cfq_exit_queue() */
k = __cic->key;
if (unlikely(!k)) {
cfq_drop_dead_cic(ioc, cic);
goto restart;
}
if (cic->key < k)
p = &(*p)->rb_left;
else if (cic->key > k)
p = &(*p)->rb_right;
else
BUG();
}
spin_lock(&cfq_exit_lock);
rb_link_node(&cic->rb_node, parent, p);
rb_insert_color(&cic->rb_node, &ioc->cic_root);
list_add(&cic->queue_list, &cfqd->cic_list);
spin_unlock(&cfq_exit_lock);
}
/*
* Setup general io context and cfq io context. There can be several cfq
* io contexts per general io context, if this process is doing io to more
* than one device managed by cfq.
cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
struct io_context *ioc = NULL;
might_sleep_if(gfp_mask & __GFP_WAIT);
ioc = get_io_context(gfp_mask);
cic = cfq_cic_rb_lookup(cfqd, ioc);
if (cic)
goto out;
cic = cfq_alloc_io_context(cfqd, gfp_mask);
if (cic == NULL)
goto err;
cfq_cic_link(cfqd, ioc, cic);
out:
return cic;
err:
put_io_context(ioc);
return NULL;
}
static void
cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
unsigned long elapsed, ttime;
/*
* if this context already has stuff queued, thinktime is from
* last queue not last end
*/
#if 0
if (time_after(cic->last_end_request, cic->last_queue))
elapsed = jiffies - cic->last_end_request;
else
elapsed = jiffies - cic->last_queue;
#else
elapsed = jiffies - cic->last_end_request;
#endif
ttime = min(elapsed, 2UL * cfqd->cfq_slice_idle);
cic->ttime_samples = (7*cic->ttime_samples + 256) / 8;
cic->ttime_total = (7*cic->ttime_total + 256*ttime) / 8;
cic->ttime_mean = (cic->ttime_total + 128) / cic->ttime_samples;
}
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
static void
cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
struct cfq_rq *crq)
{
sector_t sdist;
u64 total;
if (cic->last_request_pos < crq->request->sector)
sdist = crq->request->sector - cic->last_request_pos;
else
sdist = cic->last_request_pos - crq->request->sector;
/*
* Don't allow the seek distance to get too large from the
* odd fragment, pagein, etc
*/
if (cic->seek_samples <= 60) /* second&third seek */
sdist = min(sdist, (cic->seek_mean * 4) + 2*1024*1024);
else
sdist = min(sdist, (cic->seek_mean * 4) + 2*1024*64);
cic->seek_samples = (7*cic->seek_samples + 256) / 8;
cic->seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
total = cic->seek_total + (cic->seek_samples/2);
do_div(total, cic->seek_samples);
cic->seek_mean = (sector_t)total;
}
/*
* Disable idle window if the process thinks too long or seeks so much that
* it doesn't matter
*/
static void
cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_io_context *cic)
{
int enable_idle = cfq_cfqq_idle_window(cfqq);
if (!cic->ioc->task || !cfqd->cfq_slice_idle || cfqd->hw_tag)
enable_idle = 0;
else if (sample_valid(cic->ttime_samples)) {
if (cic->ttime_mean > cfqd->cfq_slice_idle)
enable_idle = 0;
else
enable_idle = 1;
if (enable_idle)
cfq_mark_cfqq_idle_window(cfqq);
else
cfq_clear_cfqq_idle_window(cfqq);
/*
* Check if new_cfqq should preempt the currently active queue. Return 0 for
* no or if we aren't sure, a 1 will cause a preempt.
*/
static int
cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
struct cfq_rq *crq)
{
struct cfq_queue *cfqq = cfqd->active_queue;
if (cfq_class_idle(new_cfqq))
return 0;
if (!cfqq)
return 1;
if (cfq_class_idle(cfqq))
return 1;
return 0;
/*
* if it doesn't have slice left, forget it
*/
if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
return 0;
if (cfq_crq_is_sync(crq) && !cfq_cfqq_sync(cfqq))
return 1;
return 0;
}
/*
* cfqq preempts the active queue. if we allowed preempt with no slice left,
* let it have half of its nominal slice.
*/
static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
struct cfq_queue *__cfqq, *next;
list_for_each_entry_safe(__cfqq, next, &cfqd->cur_rr, cfq_list)
cfq_resort_rr_list(__cfqq, 1);
if (!cfqq->slice_left)
cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
cfqq->slice_end = cfqq->slice_left + jiffies;
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
__cfq_set_active_queue(cfqd, cfqq);
}
/*
* should really be a ll_rw_blk.c helper
*/
static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
request_queue_t *q = cfqd->queue;
if (!blk_queue_plugged(q))
q->request_fn(q);
else
__generic_unplug_device(q);
}
/*
* Called when a new fs request (crq) is added (to cfqq). Check if there's
* something we should do about it
*/
static void
cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_rq *crq)
{
cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
cic = crq->io_context;
/*
* we never wait for an async request and we don't allow preemption
* of an async request. so just return early
*/
if (!cfq_crq_is_sync(crq)) {
/*
* sync process issued an async request, if it's waiting
* then expire it and kick rq handling.
*/
if (cic == cfqd->active_cic &&
del_timer(&cfqd->idle_slice_timer)) {
cfq_slice_expired(cfqd, 0);
cfq_start_queueing(cfqd, cfqq);
}
cfq_update_io_seektime(cfqd, cic, crq);
cfq_update_idle_window(cfqd, cfqq, cic);
cic->last_queue = jiffies;
cic->last_request_pos = crq->request->sector + crq->request->nr_sectors;
if (cfqq == cfqd->active_queue) {
/*
* if we are waiting for a request for this queue, let it rip
* immediately and flag that we must not expire this queue
* just now
*/
if (cfq_cfqq_wait_request(cfqq)) {
cfq_mark_cfqq_must_dispatch(cfqq);
del_timer(&cfqd->idle_slice_timer);
cfq_start_queueing(cfqd, cfqq);
}
} else if (cfq_should_preempt(cfqd, cfqq, crq)) {
/*
* not the active queue - expire current slice if it is
* idle and has expired it's mean thinktime or this new queue
* has some old slice time left and is of higher priority
*/
cfq_preempt_queue(cfqd, cfqq);
cfq_start_queueing(cfqd, cfqq);
}
static void cfq_insert_request(request_queue_t *q, struct request *rq)
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_rq *crq = RQ_DATA(rq);
struct cfq_queue *cfqq = crq->cfq_queue;
cfq_init_prio_data(cfqq);
list_add_tail(&rq->queuelist, &cfqq->fifo);
if (rq_mergeable(rq))
cfq_add_crq_hash(cfqd, crq);
cfq_crq_enqueued(cfqd, cfqq, crq);
}
static void cfq_completed_request(request_queue_t *q, struct request *rq)
{
struct cfq_rq *crq = RQ_DATA(rq);
struct cfq_queue *cfqq = crq->cfq_queue;
struct cfq_data *cfqd = cfqq->cfqd;
const int sync = cfq_crq_is_sync(crq);
unsigned long now;
now = jiffies;
WARN_ON(!cfqd->rq_in_driver);
WARN_ON(!cfqq->on_dispatch[sync]);
cfqd->rq_in_driver--;
cfqq->on_dispatch[sync]--;
if (!cfq_class_idle(cfqq))
cfqd->last_end_request = now;
if (!cfq_cfqq_dispatched(cfqq)) {
if (cfq_cfqq_on_rr(cfqq)) {
cfqq->service_last = now;
cfq_resort_rr_list(cfqq, 0);
}
if (cfq_crq_is_sync(crq))
crq->io_context->last_end_request = now;
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
}
static struct request *
cfq_former_request(request_queue_t *q, struct request *rq)
{
struct cfq_rq *crq = RQ_DATA(rq);
struct rb_node *rbprev = rb_prev(&crq->rb_node);
if (rbprev)
return rb_entry_crq(rbprev)->request;
return NULL;
}
static struct request *
cfq_latter_request(request_queue_t *q, struct request *rq)
{
struct cfq_rq *crq = RQ_DATA(rq);
struct rb_node *rbnext = rb_next(&crq->rb_node);
if (rbnext)
return rb_entry_crq(rbnext)->request;
return NULL;
}
/*
* we temporarily boost lower priority queues if they are holding fs exclusive
* resources. they are boosted to normal prio (CLASS_BE/4)
*/
static void cfq_prio_boost(struct cfq_queue *cfqq)
const int ioprio_class = cfqq->ioprio_class;
const int ioprio = cfqq->ioprio;
if (has_fs_excl()) {
/*
* boost idle prio on transactions that would lock out other
* users of the filesystem
*/
if (cfq_class_idle(cfqq))
cfqq->ioprio_class = IOPRIO_CLASS_BE;
if (cfqq->ioprio > IOPRIO_NORM)
cfqq->ioprio = IOPRIO_NORM;
} else {
/*
* check if we need to unboost the queue
*/
if (cfqq->ioprio_class != cfqq->org_ioprio_class)
cfqq->ioprio_class = cfqq->org_ioprio_class;
if (cfqq->ioprio != cfqq->org_ioprio)
cfqq->ioprio = cfqq->org_ioprio;
}
/*
* refile between round-robin lists if we moved the priority class
*/
if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio) &&
cfq_resort_rr_list(cfqq, 0);
}
static inline int
__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct task_struct *task, int rw)
{
if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
return ELV_MQUEUE_MUST;
return ELV_MQUEUE_MAY;
}
static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
struct cfq_queue *cfqq;
/*
* don't force setup of a queue from here, as a call to may_queue
* does not necessarily imply that a request actually will be queued.
* so just lookup a possibly existing queue, or return 'may queue'
* if that fails
*/
cfqq = cfq_find_cfq_hash(cfqd, cfq_queue_pid(tsk, rw), tsk->ioprio);
if (cfqq) {
cfq_init_prio_data(cfqq);
cfq_prio_boost(cfqq);
return __cfq_may_queue(cfqd, cfqq, tsk, rw);
}
return ELV_MQUEUE_MAY;
}
static void cfq_check_waiters(request_queue_t *q, struct cfq_queue *cfqq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
if (unlikely(cfqd->rq_starved)) {
struct request_list *rl = &q->rq;
smp_mb();
if (waitqueue_active(&rl->wait[READ]))
wake_up(&rl->wait[READ]);
if (waitqueue_active(&rl->wait[WRITE]))
wake_up(&rl->wait[WRITE]);
}
}
/*
* queue lock held here
*/
static void cfq_put_request(request_queue_t *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_rq *crq = RQ_DATA(rq);
if (crq) {
struct cfq_queue *cfqq = crq->cfq_queue;
const int rw = rq_data_dir(rq);
BUG_ON(!cfqq->allocated[rw]);
cfqq->allocated[rw]--;
put_io_context(crq->io_context->ioc);
mempool_free(crq, cfqd->crq_pool);
rq->elevator_private = NULL;
cfq_check_waiters(q, cfqq);
cfq_put_queue(cfqq);
}
}
/*
* Allocate cfq data structures associated with this request.
static int
cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_io_context *cic;
const int rw = rq_data_dir(rq);
struct cfq_queue *cfqq;
int is_sync = key != CFQ_KEY_ASYNC;
cic = cfq_get_io_context(cfqd, gfp_mask);