block: move existing elevator ops to union
[sfrench/cifs-2.6.git] / block / cfq-iosched.c
index cc2f6dbd43032644313fe12fba25276a46730892..37aeb20fa454a44bbe017cdfdce3383d0e19776e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/blktrace_api.h>
 #include <linux/blk-cgroup.h>
 #include "blk.h"
+#include "blk-wbt.h"
 
 /*
  * tunables
@@ -667,10 +668,10 @@ static inline void cfqg_put(struct cfq_group *cfqg)
 } while (0)
 
 static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg,
-                                           struct cfq_group *curr_cfqg, int op,
-                                           int op_flags)
+                                           struct cfq_group *curr_cfqg,
+                                           unsigned int op)
 {
-       blkg_rwstat_add(&cfqg->stats.queued, op, op_flags, 1);
+       blkg_rwstat_add(&cfqg->stats.queued, op, 1);
        cfqg_stats_end_empty_time(&cfqg->stats);
        cfqg_stats_set_start_group_wait_time(cfqg, curr_cfqg);
 }
@@ -684,30 +685,29 @@ static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg,
 #endif
 }
 
-static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int op,
-                                              int op_flags)
+static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg,
+                                              unsigned int op)
 {
-       blkg_rwstat_add(&cfqg->stats.queued, op, op_flags, -1);
+       blkg_rwstat_add(&cfqg->stats.queued, op, -1);
 }
 
-static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int op,
-                                              int op_flags)
+static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg,
+                                              unsigned int op)
 {
-       blkg_rwstat_add(&cfqg->stats.merged, op, op_flags, 1);
+       blkg_rwstat_add(&cfqg->stats.merged, op, 1);
 }
 
 static inline void cfqg_stats_update_completion(struct cfq_group *cfqg,
-                       uint64_t start_time, uint64_t io_start_time, int op,
-                       int op_flags)
+                       uint64_t start_time, uint64_t io_start_time,
+                       unsigned int op)
 {
        struct cfqg_stats *stats = &cfqg->stats;
        unsigned long long now = sched_clock();
 
        if (time_after64(now, io_start_time))
-               blkg_rwstat_add(&stats->service_time, op, op_flags,
-                               now - io_start_time);
+               blkg_rwstat_add(&stats->service_time, op, now - io_start_time);
        if (time_after64(io_start_time, start_time))
-               blkg_rwstat_add(&stats->wait_time, op, op_flags,
+               blkg_rwstat_add(&stats->wait_time, op,
                                io_start_time - start_time);
 }
 
@@ -786,16 +786,16 @@ static inline void cfqg_put(struct cfq_group *cfqg) { }
 #define cfq_log_cfqg(cfqd, cfqg, fmt, args...)         do {} while (0)
 
 static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg,
-                       struct cfq_group *curr_cfqg, int op, int op_flags) { }
+                       struct cfq_group *curr_cfqg, unsigned int op) { }
 static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg,
                        uint64_t time, unsigned long unaccounted_time) { }
-static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int op,
-                       int op_flags) { }
-static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int op,
-                       int op_flags) { }
+static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg,
+                       unsigned int op) { }
+static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg,
+                       unsigned int op) { }
 static inline void cfqg_stats_update_completion(struct cfq_group *cfqg,
-                       uint64_t start_time, uint64_t io_start_time, int op,
-                       int op_flags) { }
+                       uint64_t start_time, uint64_t io_start_time,
+                       unsigned int op) { }
 
 #endif /* CONFIG_CFQ_GROUP_IOSCHED */
 
@@ -912,15 +912,6 @@ static inline struct cfq_data *cic_to_cfqd(struct cfq_io_cq *cic)
        return cic->icq.q->elevator->elevator_data;
 }
 
-/*
- * We regard a request as SYNC, if it's either a read or has the SYNC bit
- * set (in which case it could also be direct WRITE).
- */
-static inline bool cfq_bio_sync(struct bio *bio)
-{
-       return bio_data_dir(bio) == READ || (bio->bi_opf & REQ_SYNC);
-}
-
 /*
  * scheduler run of queue, if there are requests pending and no one in the
  * driver that will restart queueing
@@ -1596,7 +1587,7 @@ static struct blkcg_policy_data *cfq_cpd_alloc(gfp_t gfp)
 {
        struct cfq_group_data *cgd;
 
-       cgd = kzalloc(sizeof(*cgd), GFP_KERNEL);
+       cgd = kzalloc(sizeof(*cgd), gfp);
        if (!cgd)
                return NULL;
        return &cgd->cpd;
@@ -2474,10 +2465,10 @@ 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)]--;
-       cfqg_stats_update_io_remove(RQ_CFQG(rq), req_op(rq), rq->cmd_flags);
+       cfqg_stats_update_io_remove(RQ_CFQG(rq), rq->cmd_flags);
        cfq_add_rq_rb(rq);
        cfqg_stats_update_io_add(RQ_CFQG(rq), cfqq->cfqd->serving_group,
-                                req_op(rq), rq->cmd_flags);
+                                rq->cmd_flags);
 }
 
 static struct request *
@@ -2491,7 +2482,7 @@ cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
        if (!cic)
                return NULL;
 
-       cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
+       cfqq = cic_to_cfqq(cic, op_is_sync(bio->bi_opf));
        if (cfqq)
                return elv_rb_find(&cfqq->sort_list, bio_end_sector(bio));
 
@@ -2530,7 +2521,7 @@ static void cfq_remove_request(struct request *rq)
        cfq_del_rq_rb(rq);
 
        cfqq->cfqd->rq_queued--;
-       cfqg_stats_update_io_remove(RQ_CFQG(rq), req_op(rq), rq->cmd_flags);
+       cfqg_stats_update_io_remove(RQ_CFQG(rq), rq->cmd_flags);
        if (rq->cmd_flags & REQ_PRIO) {
                WARN_ON(!cfqq->prio_pending);
                cfqq->prio_pending--;
@@ -2565,7 +2556,7 @@ 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)
 {
-       cfqg_stats_update_io_merged(RQ_CFQG(req), bio_op(bio), bio->bi_opf);
+       cfqg_stats_update_io_merged(RQ_CFQG(req), bio->bi_opf);
 }
 
 static void
@@ -2588,7 +2579,7 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
        if (cfqq->next_rq == next)
                cfqq->next_rq = rq;
        cfq_remove_request(next);
-       cfqg_stats_update_io_merged(RQ_CFQG(rq), req_op(next), next->cmd_flags);
+       cfqg_stats_update_io_merged(RQ_CFQG(rq), next->cmd_flags);
 
        cfqq = RQ_CFQQ(next);
        /*
@@ -2605,13 +2596,14 @@ static int cfq_allow_bio_merge(struct request_queue *q, struct request *rq,
                               struct bio *bio)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
+       bool is_sync = op_is_sync(bio->bi_opf);
        struct cfq_io_cq *cic;
        struct cfq_queue *cfqq;
 
        /*
         * Disallow merge of a sync bio into an async request.
         */
-       if (cfq_bio_sync(bio) && !rq_is_sync(rq))
+       if (is_sync && !rq_is_sync(rq))
                return false;
 
        /*
@@ -2622,7 +2614,7 @@ static int cfq_allow_bio_merge(struct request_queue *q, struct request *rq,
        if (!cic)
                return false;
 
-       cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
+       cfqq = cic_to_cfqq(cic, is_sync);
        return cfqq == RQ_CFQQ(rq);
 }
 
@@ -3042,7 +3034,6 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
        if (ktime_get_ns() < rq->fifo_time)
                rq = NULL;
 
-       cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
        return rq;
 }
 
@@ -3420,6 +3411,9 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        unsigned int max_dispatch;
 
+       if (cfq_cfqq_must_dispatch(cfqq))
+               return true;
+
        /*
         * Drain async requests before we start sync IO
         */
@@ -3511,15 +3505,20 @@ static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 
        BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
 
+       rq = cfq_check_fifo(cfqq);
+       if (rq)
+               cfq_mark_cfqq_must_dispatch(cfqq);
+
        if (!cfq_may_dispatch(cfqd, cfqq))
                return false;
 
        /*
         * follow expired path, else get first next available
         */
-       rq = cfq_check_fifo(cfqq);
        if (!rq)
                rq = cfqq->next_rq;
+       else
+               cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
 
        /*
         * insert request into driver dispatch list
@@ -3764,9 +3763,11 @@ static void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio)
        struct cfq_data *cfqd = cic_to_cfqd(cic);
        struct cfq_queue *cfqq;
        uint64_t serial_nr;
+       bool nonroot_cg;
 
        rcu_read_lock();
        serial_nr = bio_blkcg(bio)->css.serial_nr;
+       nonroot_cg = bio_blkcg(bio) != &blkcg_root;
        rcu_read_unlock();
 
        /*
@@ -3776,6 +3777,14 @@ static void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio)
        if (unlikely(!cfqd) || likely(cic->blkcg_serial_nr == serial_nr))
                return;
 
+       /*
+        * If we have a non-root cgroup, we can depend on that to
+        * do proper throttling of writes. Turn off wbt for that
+        * case, if it was enabled by default.
+        */
+       if (nonroot_cg)
+               wbt_disable_default(cfqd->queue);
+
        /*
         * Drop reference to queues.  New queues will be assigned in new
         * group upon arrival of fresh requests.
@@ -3847,7 +3856,8 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic,
                        goto out;
        }
 
-       cfqq = kmem_cache_alloc_node(cfq_pool, GFP_NOWAIT | __GFP_ZERO,
+       cfqq = kmem_cache_alloc_node(cfq_pool,
+                                    GFP_NOWAIT | __GFP_ZERO | __GFP_NOWARN,
                                     cfqd->queue->node);
        if (!cfqq) {
                cfqq = &cfqd->oom_cfqq;
@@ -3916,6 +3926,12 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfqq->seek_history |= (sdist > CFQQ_SEEK_THR);
 }
 
+static inline bool req_noidle(struct request *req)
+{
+       return req_op(req) == REQ_OP_WRITE &&
+               (req->cmd_flags & (REQ_SYNC | REQ_IDLE)) == REQ_SYNC;
+}
+
 /*
  * Disable idle window if the process thinks too long or seeks so much that
  * it doesn't matter
@@ -3937,7 +3953,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        if (cfqq->queued[0] + cfqq->queued[1] >= 4)
                cfq_mark_cfqq_deep(cfqq);
 
-       if (cfqq->next_rq && (cfqq->next_rq->cmd_flags & REQ_NOIDLE))
+       if (cfqq->next_rq && req_noidle(cfqq->next_rq))
                enable_idle = 0;
        else if (!atomic_read(&cic->icq.ioc->active_ref) ||
                 !cfqd->cfq_slice_idle ||
@@ -3989,7 +4005,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
         * if the new request is sync, but the currently running queue is
         * not, let the sync request have priority.
         */
-       if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
+       if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq) && !cfq_cfqq_must_dispatch(cfqq))
                return true;
 
        /*
@@ -4135,7 +4151,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
        rq->fifo_time = ktime_get_ns() + cfqd->cfq_fifo_expire[rq_is_sync(rq)];
        list_add_tail(&rq->queuelist, &cfqq->fifo);
        cfq_add_rq_rb(rq);
-       cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group, req_op(rq),
+       cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group,
                                 rq->cmd_flags);
        cfq_rq_enqueued(cfqd, cfqq, rq);
 }
@@ -4222,8 +4238,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        const int sync = rq_is_sync(rq);
        u64 now = ktime_get_ns();
 
-       cfq_log_cfqq(cfqd, cfqq, "complete rqnoidle %d",
-                    !!(rq->cmd_flags & REQ_NOIDLE));
+       cfq_log_cfqq(cfqd, cfqq, "complete rqnoidle %d", req_noidle(rq));
 
        cfq_update_hw_tag(cfqd);
 
@@ -4233,8 +4248,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        cfqq->dispatched--;
        (RQ_CFQG(rq))->dispatched--;
        cfqg_stats_update_completion(cfqq->cfqg, rq_start_time_ns(rq),
-                                    rq_io_start_time_ns(rq), req_op(rq),
-                                    rq->cmd_flags);
+                                    rq_io_start_time_ns(rq), rq->cmd_flags);
 
        cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--;
 
@@ -4312,14 +4326,14 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
                cfq_schedule_dispatch(cfqd);
 }
 
-static void cfqq_boost_on_prio(struct cfq_queue *cfqq, int op_flags)
+static void cfqq_boost_on_prio(struct cfq_queue *cfqq, unsigned int op)
 {
        /*
         * If REQ_PRIO is set, boost class and prio level, if it's below
         * BE/NORM. If prio is not set, restore the potentially boosted
         * class/prio level.
         */
-       if (!(op_flags & REQ_PRIO)) {
+       if (!(op & REQ_PRIO)) {
                cfqq->ioprio_class = cfqq->org_ioprio_class;
                cfqq->ioprio = cfqq->org_ioprio;
        } else {
@@ -4340,7 +4354,7 @@ static inline int __cfq_may_queue(struct cfq_queue *cfqq)
        return ELV_MQUEUE_MAY;
 }
 
-static int cfq_may_queue(struct request_queue *q, int op, int op_flags)
+static int cfq_may_queue(struct request_queue *q, unsigned int op)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
        struct task_struct *tsk = current;
@@ -4357,10 +4371,10 @@ static int cfq_may_queue(struct request_queue *q, int op, int op_flags)
        if (!cic)
                return ELV_MQUEUE_MAY;
 
-       cfqq = cic_to_cfqq(cic, rw_is_sync(op, op_flags));
+       cfqq = cic_to_cfqq(cic, op_is_sync(op));
        if (cfqq) {
                cfq_init_prio_data(cfqq, cic);
-               cfqq_boost_on_prio(cfqq, op_flags);
+               cfqq_boost_on_prio(cfqq, op);
 
                return __cfq_may_queue(cfqq);
        }
@@ -4823,7 +4837,7 @@ static struct elv_fs_entry cfq_attrs[] = {
 };
 
 static struct elevator_type iosched_cfq = {
-       .ops = {
+       .ops.sq = {
                .elevator_merge_fn =            cfq_merge,
                .elevator_merged_fn =           cfq_merged_request,
                .elevator_merge_req_fn =        cfq_merged_requests,