Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / block / cfq-iosched.c
index f6d3155..3c38536 100644 (file)
@@ -59,7 +59,6 @@ static const int cfq_hist_divisor = 4;
 #define RQ_CFQG(rq)            (struct cfq_group *) ((rq)->elv.priv[1])
 
 static struct kmem_cache *cfq_pool;
-static struct kmem_cache *cfq_icq_pool;
 
 #define CFQ_PRIO_LISTS         IOPRIO_BE_NR
 #define cfq_class_idle(cfqq)   ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
@@ -296,6 +295,7 @@ struct cfq_data {
        unsigned int cfq_slice_idle;
        unsigned int cfq_group_idle;
        unsigned int cfq_latency;
+       unsigned int cfq_target_latency;
 
        /*
         * Fallback dummy cfqq for extreme OOM conditions
@@ -605,7 +605,7 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg)
 {
        struct cfq_rb_root *st = &cfqd->grp_service_tree;
 
-       return cfq_target_latency * cfqg->weight / st->total_weight;
+       return cfqd->cfq_target_latency * cfqg->weight / st->total_weight;
 }
 
 static inline unsigned
@@ -1657,6 +1657,8 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
                    struct request *next)
 {
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
+       struct cfq_data *cfqd = q->elevator->elevator_data;
+
        /*
         * reposition in fifo if next is older than rq
         */
@@ -1671,6 +1673,16 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
        cfq_remove_request(next);
        cfq_blkiocg_update_io_merged_stats(&(RQ_CFQG(rq))->blkg,
                                        rq_data_dir(next), rq_is_sync(next));
+
+       cfqq = RQ_CFQQ(next);
+       /*
+        * all requests of this queue are merged to other queues, delete it
+        * from the service tree. If it's the active_queue,
+        * cfq_dispatch_requests() will choose to expire it or do idle
+        */
+       if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list) &&
+           cfqq != cfqd->active_queue)
+               cfq_del_cfqq_rr(cfqd, cfqq);
 }
 
 static int cfq_allow_merge(struct request_queue *q, struct request *rq,
@@ -1688,18 +1700,11 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
 
        /*
         * Lookup the cfqq that this bio will be queued with and allow
-        * merge only if rq is queued there.  This function can be called
-        * from plug merge without queue_lock.  In such cases, ioc of @rq
-        * and %current are guaranteed to be equal.  Avoid lookup which
-        * requires queue_lock by using @rq's cic.
+        * merge only if rq is queued there.
         */
-       if (current->io_context == RQ_CIC(rq)->icq.ioc) {
-               cic = RQ_CIC(rq);
-       } else {
-               cic = cfq_cic_lookup(cfqd, current->io_context);
-               if (!cic)
-                       return false;
-       }
+       cic = cfq_cic_lookup(cfqd, current->io_context);
+       if (!cic)
+               return false;
 
        cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
        return cfqq == RQ_CFQQ(rq);
@@ -1783,7 +1788,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfqd->active_queue = NULL;
 
        if (cfqd->active_cic) {
-               put_io_context(cfqd->active_cic->icq.ioc, cfqd->queue);
+               put_io_context(cfqd->active_cic->icq.ioc);
                cfqd->active_cic = NULL;
        }
 }
@@ -2267,7 +2272,8 @@ new_workload:
                 * to have higher weight. A more accurate thing would be to
                 * calculate system wide asnc/sync ratio.
                 */
-               tmp = cfq_target_latency * cfqg_busy_async_queues(cfqd, cfqg);
+               tmp = cfqd->cfq_target_latency *
+                       cfqg_busy_async_queues(cfqd, cfqg);
                tmp = tmp/cfqd->busy_queues;
                slice = min_t(unsigned, slice, tmp);
 
@@ -2707,6 +2713,13 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        cfq_put_queue(cfqq);
 }
 
+static void cfq_init_icq(struct io_cq *icq)
+{
+       struct cfq_io_cq *cic = icq_to_cic(icq);
+
+       cic->ttime.last_end_request = jiffies;
+}
+
 static void cfq_exit_icq(struct io_cq *icq)
 {
        struct cfq_io_cq *cic = icq_to_cic(icq);
@@ -2723,21 +2736,6 @@ static void cfq_exit_icq(struct io_cq *icq)
        }
 }
 
-static struct cfq_io_cq *cfq_alloc_cic(struct cfq_data *cfqd, gfp_t gfp_mask)
-{
-       struct cfq_io_cq *cic;
-
-       cic = kmem_cache_alloc_node(cfq_icq_pool, gfp_mask | __GFP_ZERO,
-                                                       cfqd->queue->node);
-       if (cic) {
-               cic->ttime.last_end_request = jiffies;
-               INIT_LIST_HEAD(&cic->icq.q_node);
-               INIT_HLIST_NODE(&cic->icq.ioc_node);
-       }
-
-       return cic;
-}
-
 static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
 {
        struct task_struct *tsk = current;
@@ -2944,120 +2942,6 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc,
        return cfqq;
 }
 
-/**
- * cfq_create_cic - create and link a cfq_io_cq
- * @cfqd: cfqd of interest
- * @gfp_mask: allocation mask
- *
- * Make sure cfq_io_cq linking %current->io_context and @cfqd exists.  If
- * ioc and/or cic doesn't exist, they will be created using @gfp_mask.
- */
-static int cfq_create_cic(struct cfq_data *cfqd, gfp_t gfp_mask)
-{
-       struct request_queue *q = cfqd->queue;
-       struct io_cq *icq = NULL;
-       struct cfq_io_cq *cic;
-       struct io_context *ioc;
-       int ret = -ENOMEM;
-
-       might_sleep_if(gfp_mask & __GFP_WAIT);
-
-       /* allocate stuff */
-       ioc = create_io_context(current, gfp_mask, q->node);
-       if (!ioc)
-               goto out;
-
-       cic = cfq_alloc_cic(cfqd, gfp_mask);
-       if (!cic)
-               goto out;
-       icq = &cic->icq;
-
-       ret = radix_tree_preload(gfp_mask);
-       if (ret)
-               goto out;
-
-       icq->ioc = ioc;
-       icq->q = cfqd->queue;
-
-       /* lock both q and ioc and try to link @icq */
-       spin_lock_irq(q->queue_lock);
-       spin_lock(&ioc->lock);
-
-       ret = radix_tree_insert(&ioc->icq_tree, q->id, icq);
-       if (likely(!ret)) {
-               hlist_add_head(&icq->ioc_node, &ioc->icq_list);
-               list_add(&icq->q_node, &q->icq_list);
-               icq = NULL;
-       } else if (ret == -EEXIST) {
-               /* someone else already did it */
-               ret = 0;
-       }
-
-       spin_unlock(&ioc->lock);
-       spin_unlock_irq(q->queue_lock);
-
-       radix_tree_preload_end();
-out:
-       if (ret)
-               printk(KERN_ERR "cfq: icq link failed!\n");
-       if (icq)
-               kmem_cache_free(cfq_icq_pool, icq);
-       return ret;
-}
-
-/**
- * cfq_get_cic - acquire cfq_io_cq and bump refcnt on io_context
- * @cfqd: cfqd to setup cic for
- * @gfp_mask: allocation mask
- *
- * Return cfq_io_cq associating @cfqd and %current->io_context and
- * bump refcnt on io_context.  If ioc or cic doesn't exist, they're created
- * using @gfp_mask.
- *
- * Must be called under queue_lock which may be released and re-acquired.
- * This function also may sleep depending on @gfp_mask.
- */
-static struct cfq_io_cq *cfq_get_cic(struct cfq_data *cfqd, gfp_t gfp_mask)
-{
-       struct request_queue *q = cfqd->queue;
-       struct cfq_io_cq *cic = NULL;
-       struct io_context *ioc;
-       int err;
-
-       lockdep_assert_held(q->queue_lock);
-
-       while (true) {
-               /* fast path */
-               ioc = current->io_context;
-               if (likely(ioc)) {
-                       cic = cfq_cic_lookup(cfqd, ioc);
-                       if (likely(cic))
-                               break;
-               }
-
-               /* slow path - unlock, create missing ones and retry */
-               spin_unlock_irq(q->queue_lock);
-               err = cfq_create_cic(cfqd, gfp_mask);
-               spin_lock_irq(q->queue_lock);
-               if (err)
-                       return NULL;
-       }
-
-       /* bump @ioc's refcnt and handle changed notifications */
-       get_io_context(ioc);
-
-       if (unlikely(cic->icq.changed)) {
-               if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed))
-                       changed_ioprio(cic);
-#ifdef CONFIG_CFQ_GROUP_IOSCHED
-               if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed))
-                       changed_cgroup(cic);
-#endif
-       }
-
-       return cic;
-}
-
 static void
 __cfq_update_io_thinktime(struct cfq_ttime *ttime, unsigned long slice_idle)
 {
@@ -3228,7 +3112,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
  */
 static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       struct cfq_queue *old_cfqq = cfqd->active_queue;
+       enum wl_type_t old_type = cfqq_type(cfqd->active_queue);
 
        cfq_log_cfqq(cfqd, cfqq, "preempt");
        cfq_slice_expired(cfqd, 1);
@@ -3237,7 +3121,7 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
         * workload type is changed, don't save slice, otherwise preempt
         * doesn't happen
         */
-       if (cfqq_type(old_cfqq) != cfqq_type(cfqq))
+       if (old_type != cfqq_type(cfqq))
                cfqq->cfqg->saved_workload_slice = 0;
 
        /*
@@ -3536,8 +3420,6 @@ static void cfq_put_request(struct request *rq)
                BUG_ON(!cfqq->allocated[rw]);
                cfqq->allocated[rw]--;
 
-               put_io_context(RQ_CIC(rq)->icq.ioc, cfqq->cfqd->queue);
-
                /* Put down rq reference on cfqg */
                cfq_put_cfqg(RQ_CFQG(rq));
                rq->elv.priv[0] = NULL;
@@ -3586,17 +3468,24 @@ static int
 cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_io_cq *cic;
+       struct cfq_io_cq *cic = icq_to_cic(rq->elv.icq);
        const int rw = rq_data_dir(rq);
        const bool is_sync = rq_is_sync(rq);
        struct cfq_queue *cfqq;
+       unsigned int changed;
 
        might_sleep_if(gfp_mask & __GFP_WAIT);
 
        spin_lock_irq(q->queue_lock);
-       cic = cfq_get_cic(cfqd, gfp_mask);
-       if (!cic)
-               goto queue_fail;
+
+       /* handle changed notifications */
+       changed = icq_get_changed(&cic->icq);
+       if (unlikely(changed & ICQ_IOPRIO_CHANGED))
+               changed_ioprio(cic);
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       if (unlikely(changed & ICQ_CGROUP_CHANGED))
+               changed_cgroup(cic);
+#endif
 
 new_queue:
        cfqq = cic_to_cfqq(cic, is_sync);
@@ -3627,17 +3516,10 @@ new_queue:
        cfqq->allocated[rw]++;
 
        cfqq->ref++;
-       rq->elv.icq = &cic->icq;
        rq->elv.priv[0] = cfqq;
        rq->elv.priv[1] = cfq_ref_get_cfqg(cfqq->cfqg);
        spin_unlock_irq(q->queue_lock);
        return 0;
-
-queue_fail:
-       cfq_schedule_dispatch(cfqd);
-       spin_unlock_irq(q->queue_lock);
-       cfq_log(cfqd, "set_request fail");
-       return 1;
 }
 
 static void cfq_kick_queue(struct work_struct *work)
@@ -3857,6 +3739,7 @@ static void *cfq_init_queue(struct request_queue *q)
        cfqd->cfq_back_penalty = cfq_back_penalty;
        cfqd->cfq_slice[0] = cfq_slice_async;
        cfqd->cfq_slice[1] = cfq_slice_sync;
+       cfqd->cfq_target_latency = cfq_target_latency;
        cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
        cfqd->cfq_slice_idle = cfq_slice_idle;
        cfqd->cfq_group_idle = cfq_group_idle;
@@ -3908,6 +3791,7 @@ SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
 SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
 SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
 SHOW_FUNCTION(cfq_low_latency_show, cfqd->cfq_latency, 0);
+SHOW_FUNCTION(cfq_target_latency_show, cfqd->cfq_target_latency, 1);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
@@ -3941,6 +3825,7 @@ STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1,
                UINT_MAX, 0);
 STORE_FUNCTION(cfq_low_latency_store, &cfqd->cfq_latency, 0, 1, 0);
+STORE_FUNCTION(cfq_target_latency_store, &cfqd->cfq_target_latency, 1, UINT_MAX, 1);
 #undef STORE_FUNCTION
 
 #define CFQ_ATTR(name) \
@@ -3958,6 +3843,7 @@ static struct elv_fs_entry cfq_attrs[] = {
        CFQ_ATTR(slice_idle),
        CFQ_ATTR(group_idle),
        CFQ_ATTR(low_latency),
+       CFQ_ATTR(target_latency),
        __ATTR_NULL
 };
 
@@ -3975,6 +3861,7 @@ static struct elevator_type iosched_cfq = {
                .elevator_completed_req_fn =    cfq_completed_request,
                .elevator_former_req_fn =       elv_rb_former_request,
                .elevator_latter_req_fn =       elv_rb_latter_request,
+               .elevator_init_icq_fn =         cfq_init_icq,
                .elevator_exit_icq_fn =         cfq_exit_icq,
                .elevator_set_req_fn =          cfq_set_request,
                .elevator_put_req_fn =          cfq_put_request,
@@ -4028,7 +3915,6 @@ static int __init cfq_init(void)
                kmem_cache_destroy(cfq_pool);
                return ret;
        }
-       cfq_icq_pool = iosched_cfq.icq_cache;
 
        blkio_policy_register(&blkio_policy_cfq);