BUG_ON(!arq->on_hash);
if (!rq_mergeable(__rq)) {
- __as_del_arq_hash(arq);
+ as_remove_merge_hints(ad->q, arq);
continue;
}
return;
}
- if (ON_RB(&arq->rb_node))
+ if (ON_RB(&arq->rb_node)) {
+ /*
+ * We'll lose the aliased request(s) here. I don't think this
+ * will ever happen, but if it does, hopefully someone will
+ * report it.
+ */
+ WARN_ON(!list_empty(&rq->queuelist));
as_remove_queued_request(q, rq);
- else
+ } else
as_remove_dispatched_request(q, rq);
}
*/
static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
{
+ struct request *rq = arq->request;
struct list_head *insert;
const int data_dir = arq->is_sync;
* This has to be set in order to be correctly updated by
* as_find_next_arq
*/
- ad->last_sector[data_dir] = arq->request->sector
- + arq->request->nr_sectors;
+ ad->last_sector[data_dir] = rq->sector + rq->nr_sectors;
if (data_dir == REQ_SYNC) {
/* In case we have to anticipate after this */
/*
* take it off the sort and fifo list, add to dispatch queue
*/
- as_remove_queued_request(ad->q, arq->request);
+ as_remove_queued_request(ad->q, rq);
insert = ad->dispatch->prev;
- while (!list_empty(&arq->request->queuelist)) {
- struct request *rq = list_entry_rq(arq->request->queuelist.next);
- struct as_rq *__arq = RQ_DATA(rq);
+ while (!list_empty(&rq->queuelist)) {
+ struct request *__rq = list_entry_rq(rq->queuelist.next);
+ struct as_rq *__arq = RQ_DATA(__rq);
- list_move_tail(&rq->queuelist, ad->dispatch);
+ list_move_tail(&__rq->queuelist, ad->dispatch);
if (__arq->io_context && __arq->io_context->aic)
atomic_inc(&__arq->io_context->aic->nr_dispatched);
ad->nr_dispatched++;
}
- list_add(&arq->request->queuelist, insert);
+ list_add(&rq->queuelist, insert);
if (arq->io_context && arq->io_context->aic)
atomic_inc(&arq->io_context->aic->nr_dispatched);
arq->state = AS_RQ_DISPATCHED;
ad->nr_dispatched++;
-
}
/*
* Link this request to that sector. They are untangled in
* as_move_to_dispatch
*/
- list_add_tail(&arq->request->queuelist, &alias->request->queuelist);
+ list_add_tail(&arq->request->queuelist, &alias->request->queuelist);
/*
* Don't want to have to handle merges.
*/
as_remove_merge_hints(ad->q, arq);
-
}
/*
as_add_request(ad, arq);
break;
default:
- printk("%s: bad insert point %d\n", __FUNCTION__,where);
+ BUG();
return;
}
}
return ELEVATOR_NO_MERGE;
out:
- q->last_merge = __rq;
+ if (rq_mergeable(__rq))
+ q->last_merge = __rq;
out_insert:
- if (ret)
- as_hot_arq_hash(ad, RQ_DATA(__rq));
+ if (ret) {
+ if (rq_mergeable(__rq))
+ as_hot_arq_hash(ad, RQ_DATA(__rq));
+ }
*req = __rq;
return ret;
}
* if the merge was a front merge, we need to reposition request
*/
if (rq_rb_key(req) != arq->rb_key) {
- struct as_rq *alias;
+ struct as_rq *alias, *next_arq = NULL;
+
+ if (ad->next_arq[arq->is_sync] == arq)
+ next_arq = as_find_next_arq(ad, arq);
/*
* Note! We should really be moving any old aliased requests
if ((alias = as_add_arq_rb(ad, arq)) ) {
list_del_init(&arq->fifo);
as_add_aliased_request(ad, arq, alias);
+ if (next_arq)
+ ad->next_arq[arq->is_sync] = next_arq;
}
/*
* Note! At this stage of this and the next function, our next
as_add_arq_hash(ad, arq);
if (rq_rb_key(req) != arq->rb_key) {
- struct as_rq *alias;
+ struct as_rq *alias, *next_arq = NULL;
+
+ if (ad->next_arq[arq->is_sync] == arq)
+ next_arq = as_find_next_arq(ad, arq);
+
as_del_arq_rb(ad, arq);
if ((alias = as_add_arq_rb(ad, arq)) ) {
list_del_init(&arq->fifo);
as_add_aliased_request(ad, arq, alias);
+ if (next_arq)
+ ad->next_arq[arq->is_sync] = next_arq;
}
}
}
}
+ /*
+ * Transfer list of aliases
+ */
+ while (!list_empty(&next->queuelist)) {
+ struct request *__rq = list_entry_rq(next->queuelist.next);
+ struct as_rq *__arq = RQ_DATA(__rq);
+
+ list_move_tail(&__rq->queuelist, &req->queuelist);
+
+ WARN_ON(__arq->state != AS_RQ_QUEUED);
+ }
+
/*
* kill knowledge of next, this one is a goner
*/