]> git.karo-electronics.de Git - linux-beck.git/blobdiff - block/cfq-iosched.c
Merge branch 'master' into for-2.6.35
[linux-beck.git] / block / cfq-iosched.c
index 023f4e69a3378cab44faefbf6c69823e6ec16b48..9e0df2bdcf2124f1f16afe645e43788e10ec9d9c 100644 (file)
@@ -7,6 +7,7 @@
  *  Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
  */
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
 #include <linux/jiffies.h>
@@ -19,7 +20,7 @@
  * tunables
  */
 /* max queue in one round of service */
-static const int cfq_quantum = 4;
+static const int cfq_quantum = 8;
 static const int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
 /* maximum backwards seek, in KiB */
 static const int cfq_back_max = 16 * 1024;
@@ -46,8 +47,10 @@ static const int cfq_hist_divisor = 4;
 #define CFQ_HW_QUEUE_MIN       (5)
 #define CFQ_SERVICE_SHIFT       12
 
-#define CFQQ_SEEK_THR          8 * 1024
-#define CFQQ_SEEKY(cfqq)       ((cfqq)->seek_mean > CFQQ_SEEK_THR)
+#define CFQQ_SEEK_THR          (sector_t)(8 * 100)
+#define CFQQ_CLOSE_THR         (sector_t)(8 * 1024)
+#define CFQQ_SECT_THR_NONROT   (sector_t)(2 * 32)
+#define CFQQ_SEEKY(cfqq)       (hweight32(cfqq->seek_history) > 32/8)
 
 #define RQ_CIC(rq)             \
        ((struct cfq_io_context *) (rq)->elevator_private)
@@ -77,11 +80,12 @@ struct cfq_rb_root {
        struct rb_root rb;
        struct rb_node *left;
        unsigned count;
+       unsigned total_weight;
        u64 min_vdisktime;
        struct rb_node *active;
-       unsigned total_weight;
 };
-#define CFQ_RB_ROOT    (struct cfq_rb_root) { RB_ROOT, NULL, 0, 0, }
+#define CFQ_RB_ROOT    (struct cfq_rb_root) { .rb = RB_ROOT, .left = NULL, \
+                       .count = 0, .min_vdisktime = 0, }
 
 /*
  * Per process-grouping structure
@@ -115,11 +119,11 @@ struct cfq_queue {
        /* time when queue got scheduled in to dispatch first request. */
        unsigned long dispatch_start;
        unsigned int allocated_slice;
+       unsigned int slice_dispatch;
        /* time when first request from queue completed and slice started. */
        unsigned long slice_start;
        unsigned long slice_end;
        long slice_resid;
-       unsigned int slice_dispatch;
 
        /* pending metadata requests */
        int meta_pending;
@@ -130,19 +134,15 @@ struct cfq_queue {
        unsigned short ioprio, org_ioprio;
        unsigned short ioprio_class, org_ioprio_class;
 
-       unsigned int seek_samples;
-       u64 seek_total;
-       sector_t seek_mean;
-       sector_t last_request_pos;
-
        pid_t pid;
 
+       u32 seek_history;
+       sector_t last_request_pos;
+
        struct cfq_rb_root *service_tree;
        struct cfq_queue *new_cfqq;
        struct cfq_group *cfqg;
        struct cfq_group *orig_cfqg;
-       /* Sectors dispatched in current dispatch round */
-       unsigned long nr_sectors;
 };
 
 /*
@@ -223,8 +223,8 @@ struct cfq_data {
 
        unsigned int busy_queues;
 
-       int rq_in_driver[2];
-       int sync_flight;
+       int rq_in_driver;
+       int rq_in_flight[2];
 
        /*
         * queue-depth detection
@@ -417,11 +417,6 @@ static struct cfq_queue *cfq_get_queue(struct cfq_data *, bool,
 static struct cfq_io_context *cfq_cic_lookup(struct cfq_data *,
                                                struct io_context *);
 
-static inline int rq_in_driver(struct cfq_data *cfqd)
-{
-       return cfqd->rq_in_driver[0] + cfqd->rq_in_driver[1];
-}
-
 static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
                                            bool is_sync)
 {
@@ -861,7 +856,7 @@ cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
        if (!RB_EMPTY_NODE(&cfqg->rb_node))
                cfq_rb_erase(&cfqg->rb_node, st);
        cfqg->saved_workload_slice = 0;
-       blkiocg_update_blkio_group_dequeue_stats(&cfqg->blkg, 1);
+       blkiocg_update_dequeue_stats(&cfqg->blkg, 1);
 }
 
 static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq)
@@ -887,13 +882,12 @@ static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq)
                        slice_used = cfqq->allocated_slice;
        }
 
-       cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u sect=%lu", slice_used,
-                               cfqq->nr_sectors);
+       cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u", slice_used);
        return slice_used;
 }
 
 static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
-                               struct cfq_queue *cfqq)
+                               struct cfq_queue *cfqq, bool forced)
 {
        struct cfq_rb_root *st = &cfqd->grp_service_tree;
        unsigned int used_sl, charge_sl;
@@ -922,8 +916,8 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
 
        cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime,
                                        st->min_vdisktime);
-       blkiocg_update_blkio_group_stats(&cfqg->blkg, used_sl,
-                                               cfqq->nr_sectors);
+       blkiocg_update_timeslice_used(&cfqg->blkg, used_sl);
+       blkiocg_set_start_empty_time(&cfqg->blkg, forced);
 }
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
@@ -951,11 +945,12 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
        struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
        unsigned int major, minor;
 
-       /* Do we need to take this reference */
-       if (!blkiocg_css_tryget(blkcg))
-               return NULL;;
-
        cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
+       if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+               cfqg->blkg.dev = MKDEV(major, minor);
+               goto done;
+       }
        if (cfqg || !create)
                goto done;
 
@@ -963,10 +958,10 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
        if (!cfqg)
                goto done;
 
-       cfqg->weight = blkcg->weight;
        for_each_cfqg_st(cfqg, i, j, st)
                *st = CFQ_RB_ROOT;
        RB_CLEAR_NODE(&cfqg->rb_node);
+       blkio_group_init(&cfqg->blkg);
 
        /*
         * Take the initial reference that will be released on destroy
@@ -980,12 +975,12 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
        sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
        blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
                                        MKDEV(major, minor));
+       cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
 
        /* Add group on cfqd list */
        hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
 
 done:
-       blkiocg_css_put(blkcg);
        return cfqg;
 }
 
@@ -1392,7 +1387,12 @@ static void cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq)
 {
        elv_rb_del(&cfqq->sort_list, rq);
        cfqq->queued[rq_is_sync(rq)]--;
+       blkiocg_update_io_remove_stats(&cfqq->cfqg->blkg, rq_data_dir(rq),
+                                               rq_is_sync(rq));
        cfq_add_rq_rb(rq);
+       blkiocg_update_io_add_stats(
+                       &cfqq->cfqg->blkg, &cfqq->cfqd->serving_group->blkg,
+                       rq_data_dir(rq), rq_is_sync(rq));
 }
 
 static struct request *
@@ -1420,9 +1420,9 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
 
-       cfqd->rq_in_driver[rq_is_sync(rq)]++;
+       cfqd->rq_in_driver++;
        cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d",
-                                               rq_in_driver(cfqd));
+                                               cfqd->rq_in_driver);
 
        cfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq);
 }
@@ -1430,12 +1430,11 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
 static void cfq_deactivate_request(struct request_queue *q, struct request *rq)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       const int sync = rq_is_sync(rq);
 
-       WARN_ON(!cfqd->rq_in_driver[sync]);
-       cfqd->rq_in_driver[sync]--;
+       WARN_ON(!cfqd->rq_in_driver);
+       cfqd->rq_in_driver--;
        cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d",
-                                               rq_in_driver(cfqd));
+                                               cfqd->rq_in_driver);
 }
 
 static void cfq_remove_request(struct request *rq)
@@ -1449,6 +1448,8 @@ static void cfq_remove_request(struct request *rq)
        cfq_del_rq_rb(rq);
 
        cfqq->cfqd->rq_queued--;
+       blkiocg_update_io_remove_stats(&cfqq->cfqg->blkg, rq_data_dir(rq),
+                                               rq_is_sync(rq));
        if (rq_is_meta(rq)) {
                WARN_ON(!cfqq->meta_pending);
                cfqq->meta_pending--;
@@ -1480,6 +1481,14 @@ static void cfq_merged_request(struct request_queue *q, struct request *req,
        }
 }
 
+static void cfq_bio_merged(struct request_queue *q, struct request *req,
+                               struct bio *bio)
+{
+       struct cfq_queue *cfqq = RQ_CFQQ(req);
+       blkiocg_update_io_merged_stats(&cfqq->cfqg->blkg, bio_data_dir(bio),
+                                       cfq_bio_sync(bio));
+}
+
 static void
 cfq_merged_requests(struct request_queue *q, struct request *rq,
                    struct request *next)
@@ -1497,6 +1506,8 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
        if (cfqq->next_rq == next)
                cfqq->next_rq = rq;
        cfq_remove_request(next);
+       blkiocg_update_io_merged_stats(&cfqq->cfqg->blkg, rq_data_dir(next),
+                                       rq_is_sync(next));
 }
 
 static int cfq_allow_merge(struct request_queue *q, struct request *rq,
@@ -1524,17 +1535,24 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
        return cfqq == RQ_CFQQ(rq);
 }
 
+static inline void cfq_del_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       del_timer(&cfqd->idle_slice_timer);
+       blkiocg_update_idle_time_stats(&cfqq->cfqg->blkg);
+}
+
 static void __cfq_set_active_queue(struct cfq_data *cfqd,
                                   struct cfq_queue *cfqq)
 {
        if (cfqq) {
-               cfq_log_cfqq(cfqd, cfqq, "set_active");
+               cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d",
+                               cfqd->serving_prio, cfqd->serving_type);
+               blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg);
                cfqq->slice_start = 0;
                cfqq->dispatch_start = jiffies;
                cfqq->allocated_slice = 0;
                cfqq->slice_end = 0;
                cfqq->slice_dispatch = 0;
-               cfqq->nr_sectors = 0;
 
                cfq_clear_cfqq_wait_request(cfqq);
                cfq_clear_cfqq_must_dispatch(cfqq);
@@ -1542,7 +1560,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
                cfq_clear_cfqq_fifo_expire(cfqq);
                cfq_mark_cfqq_slice_new(cfqq);
 
-               del_timer(&cfqd->idle_slice_timer);
+               cfq_del_timer(cfqd, cfqq);
        }
 
        cfqd->active_queue = cfqq;
@@ -1553,12 +1571,12 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
  */
 static void
 __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-                   bool timed_out)
+                   bool timed_out, bool forced)
 {
        cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out);
 
        if (cfq_cfqq_wait_request(cfqq))
-               del_timer(&cfqd->idle_slice_timer);
+               cfq_del_timer(cfqd, cfqq);
 
        cfq_clear_cfqq_wait_request(cfqq);
        cfq_clear_cfqq_wait_busy(cfqq);
@@ -1580,7 +1598,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
        }
 
-       cfq_group_served(cfqd, cfqq->cfqg, cfqq);
+       cfq_group_served(cfqd, cfqq->cfqg, cfqq, forced);
 
        if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list))
                cfq_del_cfqq_rr(cfqd, cfqq);
@@ -1599,12 +1617,13 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        }
 }
 
-static inline void cfq_slice_expired(struct cfq_data *cfqd, bool timed_out)
+static inline void cfq_slice_expired(struct cfq_data *cfqd, bool timed_out,
+                                       bool forced)
 {
        struct cfq_queue *cfqq = cfqd->active_queue;
 
        if (cfqq)
-               __cfq_slice_expired(cfqd, cfqq, timed_out);
+               __cfq_slice_expired(cfqd, cfqq, timed_out, forced);
 }
 
 /*
@@ -1671,18 +1690,9 @@ static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
 }
 
 static inline int cfq_rq_close(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-                              struct request *rq, bool for_preempt)
+                              struct request *rq)
 {
-       sector_t sdist = cfqq->seek_mean;
-
-       if (!sample_valid(cfqq->seek_samples))
-               sdist = CFQQ_SEEK_THR;
-
-       /* if seek_mean is big, using it as close criteria is meaningless */
-       if (sdist > CFQQ_SEEK_THR && !for_preempt)
-               sdist = CFQQ_SEEK_THR;
-
-       return cfq_dist_from_last(cfqd, rq) <= sdist;
+       return cfq_dist_from_last(cfqd, rq) <= CFQQ_CLOSE_THR;
 }
 
 static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
@@ -1709,7 +1719,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
         * will contain the closest sector.
         */
        __cfqq = rb_entry(parent, struct cfq_queue, p_node);
-       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq, false))
+       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq))
                return __cfqq;
 
        if (blk_rq_pos(__cfqq->next_rq) < sector)
@@ -1720,7 +1730,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
                return NULL;
 
        __cfqq = rb_entry(node, struct cfq_queue, p_node);
-       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq, false))
+       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq))
                return __cfqq;
 
        return NULL;
@@ -1741,6 +1751,8 @@ static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd,
 {
        struct cfq_queue *cfqq;
 
+       if (cfq_class_idle(cur_cfqq))
+               return NULL;
        if (!cfq_cfqq_sync(cur_cfqq))
                return NULL;
        if (CFQQ_SEEKY(cur_cfqq))
@@ -1807,7 +1819,11 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
         * Otherwise, we do only if they are the last ones
         * in their service tree.
         */
-       return service_tree->count == 1 && cfq_cfqq_sync(cfqq);
+       if (service_tree->count == 1 && cfq_cfqq_sync(cfqq))
+               return 1;
+       cfq_log_cfqq(cfqd, cfqq, "Not idling. st->count:%d",
+                       service_tree->count);
+       return 0;
 }
 
 static void cfq_arm_slice_timer(struct cfq_data *cfqd)
@@ -1852,14 +1868,18 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
         * time slice.
         */
        if (sample_valid(cic->ttime_samples) &&
-           (cfqq->slice_end - jiffies < cic->ttime_mean))
+           (cfqq->slice_end - jiffies < cic->ttime_mean)) {
+               cfq_log_cfqq(cfqd, cfqq, "Not idling. think_time:%d",
+                               cic->ttime_mean);
                return;
+       }
 
        cfq_mark_cfqq_wait_request(cfqq);
 
        sl = cfqd->cfq_slice_idle;
 
        mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
+       blkiocg_update_set_idle_time_stats(&cfqq->cfqg->blkg);
        cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu", sl);
 }
 
@@ -1878,9 +1898,9 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
        cfqq->dispatched++;
        elv_dispatch_sort(q, rq);
 
-       if (cfq_cfqq_sync(cfqq))
-               cfqd->sync_flight++;
-       cfqq->nr_sectors += blk_rq_sectors(rq);
+       cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
+       blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq),
+                                       rq_data_dir(rq), rq_is_sync(rq));
 }
 
 /*
@@ -2062,6 +2082,7 @@ static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
                slice = max(slice, 2 * cfqd->cfq_slice_idle);
 
        slice = max_t(unsigned, slice, CFQ_MIN_TT);
+       cfq_log(cfqd, "workload slice:%d", slice);
        cfqd->workload_expires = jiffies + slice;
        cfqd->noidle_tree_requires_idle = false;
 }
@@ -2170,7 +2191,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
        }
 
 expire:
-       cfq_slice_expired(cfqd, 0);
+       cfq_slice_expired(cfqd, 0, false);
 new_queue:
        /*
         * Current queue expired. Check if we have to switch to a new
@@ -2196,7 +2217,7 @@ static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
        BUG_ON(!list_empty(&cfqq->fifo));
 
        /* By default cfqq is not expired if it is empty. Do it explicitly */
-       __cfq_slice_expired(cfqq->cfqd, cfqq, 0);
+       __cfq_slice_expired(cfqq->cfqd, cfqq, 0, true);
        return dispatched;
 }
 
@@ -2209,16 +2230,32 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
        struct cfq_queue *cfqq;
        int dispatched = 0;
 
-       while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL)
+       /* Expire the timeslice of the current active queue first */
+       cfq_slice_expired(cfqd, 0);
+       while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL) {
+               __cfq_set_active_queue(cfqd, cfqq);
                dispatched += __cfq_forced_dispatch_cfqq(cfqq);
+       }
 
-       cfq_slice_expired(cfqd, 0);
        BUG_ON(cfqd->busy_queues);
 
        cfq_log(cfqd, "forced_dispatch=%d", dispatched);
        return dispatched;
 }
 
+static inline bool cfq_slice_used_soon(struct cfq_data *cfqd,
+       struct cfq_queue *cfqq)
+{
+       /* the queue hasn't finished any request, can't estimate */
+       if (cfq_cfqq_slice_new(cfqq))
+               return 1;
+       if (time_after(jiffies + cfqd->cfq_slice_idle * cfqq->dispatched,
+               cfqq->slice_end))
+               return 1;
+
+       return 0;
+}
+
 static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        unsigned int max_dispatch;
@@ -2226,16 +2263,16 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        /*
         * Drain async requests before we start sync IO
         */
-       if (cfq_should_idle(cfqd, cfqq) && cfqd->rq_in_driver[BLK_RW_ASYNC])
+       if (cfq_should_idle(cfqd, cfqq) && cfqd->rq_in_flight[BLK_RW_ASYNC])
                return false;
 
        /*
         * If this is an async queue and we have sync IO in flight, let it wait
         */
-       if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
+       if (cfqd->rq_in_flight[BLK_RW_SYNC] && !cfq_cfqq_sync(cfqq))
                return false;
 
-       max_dispatch = cfqd->cfq_quantum;
+       max_dispatch = max_t(unsigned int, cfqd->cfq_quantum / 2, 1);
        if (cfq_class_idle(cfqq))
                max_dispatch = 1;
 
@@ -2252,13 +2289,22 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
                /*
                 * We have other queues, don't allow more IO from this one
                 */
-               if (cfqd->busy_queues > 1)
+               if (cfqd->busy_queues > 1 && cfq_slice_used_soon(cfqd, cfqq))
                        return false;
 
                /*
                 * Sole queue user, no limit
                 */
-               max_dispatch = -1;
+               if (cfqd->busy_queues == 1)
+                       max_dispatch = -1;
+               else
+                       /*
+                        * Normally we start throttling cfqq when cfq_quantum/2
+                        * requests have been dispatched. But we can drive
+                        * deeper queue depths at the beginning of slice
+                        * subjected to upper limit of cfq_quantum.
+                        * */
+                       max_dispatch = cfqd->cfq_quantum;
        }
 
        /*
@@ -2354,7 +2400,7 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
            cfqq->slice_dispatch >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
            cfq_class_idle(cfqq))) {
                cfqq->slice_end = jiffies + 1;
-               cfq_slice_expired(cfqd, 0);
+               cfq_slice_expired(cfqd, 0, false);
        }
 
        cfq_log_cfqq(cfqd, cfqq, "dispatched a request");
@@ -2385,7 +2431,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
        orig_cfqg = cfqq->orig_cfqg;
 
        if (unlikely(cfqd->active_queue == cfqq)) {
-               __cfq_slice_expired(cfqd, cfqq, 0);
+               __cfq_slice_expired(cfqd, cfqq, 0, false);
                cfq_schedule_dispatch(cfqd);
        }
 
@@ -2486,7 +2532,7 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        struct cfq_queue *__cfqq, *next;
 
        if (unlikely(cfqq == cfqd->active_queue)) {
-               __cfq_slice_expired(cfqd, cfqq, 0);
+               __cfq_slice_expired(cfqd, cfqq, 0, false);
                cfq_schedule_dispatch(cfqd);
        }
 
@@ -2980,30 +3026,20 @@ static void
 cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                       struct request *rq)
 {
-       sector_t sdist;
-       u64 total;
-
-       if (!cfqq->last_request_pos)
-               sdist = 0;
-       else if (cfqq->last_request_pos < blk_rq_pos(rq))
-               sdist = blk_rq_pos(rq) - cfqq->last_request_pos;
-       else
-               sdist = cfqq->last_request_pos - blk_rq_pos(rq);
+       sector_t sdist = 0;
+       sector_t n_sec = blk_rq_sectors(rq);
+       if (cfqq->last_request_pos) {
+               if (cfqq->last_request_pos < blk_rq_pos(rq))
+                       sdist = blk_rq_pos(rq) - cfqq->last_request_pos;
+               else
+                       sdist = cfqq->last_request_pos - blk_rq_pos(rq);
+       }
 
-       /*
-        * Don't allow the seek distance to get too large from the
-        * odd fragment, pagein, etc
-        */
-       if (cfqq->seek_samples <= 60) /* second&third seek */
-               sdist = min(sdist, (cfqq->seek_mean * 4) + 2*1024*1024);
+       cfqq->seek_history <<= 1;
+       if (blk_queue_nonrot(cfqd->queue))
+               cfqq->seek_history |= (n_sec < CFQQ_SECT_THR_NONROT);
        else
-               sdist = min(sdist, (cfqq->seek_mean * 4) + 2*1024*64);
-
-       cfqq->seek_samples = (7*cfqq->seek_samples + 256) / 8;
-       cfqq->seek_total = (7*cfqq->seek_total + (u64)256*sdist) / 8;
-       total = cfqq->seek_total + (cfqq->seek_samples/2);
-       do_div(total, cfqq->seek_samples);
-       cfqq->seek_mean = (sector_t)total;
+               cfqq->seek_history |= (sdist > CFQQ_SEEK_THR);
 }
 
 /*
@@ -3028,8 +3064,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfq_mark_cfqq_deep(cfqq);
 
        if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
-           (!cfq_cfqq_deep(cfqq) && sample_valid(cfqq->seek_samples)
-            && CFQQ_SEEKY(cfqq)))
+           (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq)))
                enable_idle = 0;
        else if (sample_valid(cic->ttime_samples)) {
                if (cic->ttime_mean > cfqd->cfq_slice_idle)
@@ -3113,7 +3148,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
         * if this request is as-good as one we would expect from the
         * current cfqq, let it preempt
         */
-       if (cfq_rq_close(cfqd, cfqq, rq, true))
+       if (cfq_rq_close(cfqd, cfqq, rq))
                return true;
 
        return false;
@@ -3126,7 +3161,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)
 {
        cfq_log_cfqq(cfqd, cfqq, "preempt");
-       cfq_slice_expired(cfqd, 1);
+       cfq_slice_expired(cfqd, 1, false);
 
        /*
         * Put the new queue at the front of the of the current list,
@@ -3174,11 +3209,14 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                if (cfq_cfqq_wait_request(cfqq)) {
                        if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE ||
                            cfqd->busy_queues > 1) {
-                               del_timer(&cfqd->idle_slice_timer);
+                               cfq_del_timer(cfqd, cfqq);
                                cfq_clear_cfqq_wait_request(cfqq);
                                __blk_run_queue(cfqd->queue);
-                       } else
+                       } else {
+                               blkiocg_update_idle_time_stats(
+                                               &cfqq->cfqg->blkg);
                                cfq_mark_cfqq_must_dispatch(cfqq);
+                       }
                }
        } else if (cfq_should_preempt(cfqd, cfqq, rq)) {
                /*
@@ -3204,6 +3242,9 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
        list_add_tail(&rq->queuelist, &cfqq->fifo);
        cfq_add_rq_rb(rq);
 
+       blkiocg_update_io_add_stats(&cfqq->cfqg->blkg,
+                       &cfqd->serving_group->blkg, rq_data_dir(rq),
+                       rq_is_sync(rq));
        cfq_rq_enqueued(cfqd, cfqq, rq);
 }
 
@@ -3215,14 +3256,14 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd)
 {
        struct cfq_queue *cfqq = cfqd->active_queue;
 
-       if (rq_in_driver(cfqd) > cfqd->hw_tag_est_depth)
-               cfqd->hw_tag_est_depth = rq_in_driver(cfqd);
+       if (cfqd->rq_in_driver > cfqd->hw_tag_est_depth)
+               cfqd->hw_tag_est_depth = cfqd->rq_in_driver;
 
        if (cfqd->hw_tag == 1)
                return;
 
        if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN &&
-           rq_in_driver(cfqd) <= CFQ_HW_QUEUE_MIN)
+           cfqd->rq_in_driver <= CFQ_HW_QUEUE_MIN)
                return;
 
        /*
@@ -3232,7 +3273,7 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd)
         */
        if (cfqq && cfq_cfqq_idle_window(cfqq) &&
            cfqq->dispatched + cfqq->queued[0] + cfqq->queued[1] <
-           CFQ_HW_QUEUE_MIN && rq_in_driver(cfqd) < CFQ_HW_QUEUE_MIN)
+           CFQ_HW_QUEUE_MIN && cfqd->rq_in_driver < CFQ_HW_QUEUE_MIN)
                return;
 
        if (cfqd->hw_tag_samples++ < 50)
@@ -3285,13 +3326,15 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
 
        cfq_update_hw_tag(cfqd);
 
-       WARN_ON(!cfqd->rq_in_driver[sync]);
+       WARN_ON(!cfqd->rq_in_driver);
        WARN_ON(!cfqq->dispatched);
-       cfqd->rq_in_driver[sync]--;
+       cfqd->rq_in_driver--;
        cfqq->dispatched--;
+       blkiocg_update_completion_stats(&cfqq->cfqg->blkg, rq_start_time_ns(rq),
+                       rq_io_start_time_ns(rq), rq_data_dir(rq),
+                       rq_is_sync(rq));
 
-       if (cfq_cfqq_sync(cfqq))
-               cfqd->sync_flight--;
+       cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--;
 
        if (sync) {
                RQ_CIC(rq)->last_end_request = now;
@@ -3318,6 +3361,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
                if (cfq_should_wait_busy(cfqd, cfqq)) {
                        cfqq->slice_end = jiffies + cfqd->cfq_slice_idle;
                        cfq_mark_cfqq_wait_busy(cfqq);
+                       cfq_log_cfqq(cfqd, cfqq, "will busy wait");
                }
 
                /*
@@ -3329,7 +3373,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
                 * - when there is a close cooperator
                 */
                if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq))
-                       cfq_slice_expired(cfqd, 1);
+                       cfq_slice_expired(cfqd, 1, false);
                else if (sync && cfqq_empty &&
                         !cfq_close_cooperator(cfqd, cfqq)) {
                        cfqd->noidle_tree_requires_idle |= !rq_noidle(rq);
@@ -3345,7 +3389,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
                }
        }
 
-       if (!rq_in_driver(cfqd))
+       if (!cfqd->rq_in_driver)
                cfq_schedule_dispatch(cfqd);
 }
 
@@ -3589,7 +3633,7 @@ static void cfq_idle_slice_timer(unsigned long data)
                cfq_clear_cfqq_deep(cfqq);
        }
 expire:
-       cfq_slice_expired(cfqd, timed_out);
+       cfq_slice_expired(cfqd, timed_out, false);
 out_kick:
        cfq_schedule_dispatch(cfqd);
 out_cont:
@@ -3632,7 +3676,7 @@ static void cfq_exit_queue(struct elevator_queue *e)
        spin_lock_irq(q->queue_lock);
 
        if (cfqd->active_queue)
-               __cfq_slice_expired(cfqd, cfqd->active_queue, 0);
+               __cfq_slice_expired(cfqd, cfqd->active_queue, 0, false);
 
        while (!list_empty(&cfqd->cic_list)) {
                struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
@@ -3859,6 +3903,7 @@ static struct elevator_type iosched_cfq = {
                .elevator_merged_fn =           cfq_merged_request,
                .elevator_merge_req_fn =        cfq_merged_requests,
                .elevator_allow_merge_fn =      cfq_allow_merge,
+               .elevator_bio_merged_fn =       cfq_bio_merged,
                .elevator_dispatch_fn =         cfq_dispatch_requests,
                .elevator_add_req_fn =          cfq_insert_request,
                .elevator_activate_req_fn =     cfq_activate_request,