remove libdss from Makefile
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / block / blk-mq-sched.c
index 0ded5e846335667406d58ce08e8439360baeb312..ae5d8f10a27c59a957911dd66fa9b68a7fc5c6e6 100644 (file)
@@ -31,11 +31,10 @@ void blk_mq_sched_free_hctx_data(struct request_queue *q,
 }
 EXPORT_SYMBOL_GPL(blk_mq_sched_free_hctx_data);
 
-static void __blk_mq_sched_assign_ioc(struct request_queue *q,
-                                     struct request *rq,
-                                     struct bio *bio,
-                                     struct io_context *ioc)
+void blk_mq_sched_assign_ioc(struct request *rq, struct bio *bio)
 {
+       struct request_queue *q = rq->q;
+       struct io_context *ioc = rq_ioc(bio);
        struct io_cq *icq;
 
        spin_lock_irq(q->queue_lock);
@@ -47,25 +46,8 @@ static void __blk_mq_sched_assign_ioc(struct request_queue *q,
                if (!icq)
                        return;
        }
-
+       get_io_context(icq->ioc);
        rq->elv.icq = icq;
-       if (!blk_mq_sched_get_rq_priv(q, rq, bio)) {
-               rq->rq_flags |= RQF_ELVPRIV;
-               get_io_context(icq->ioc);
-               return;
-       }
-
-       rq->elv.icq = NULL;
-}
-
-static void blk_mq_sched_assign_ioc(struct request_queue *q,
-                                   struct request *rq, struct bio *bio)
-{
-       struct io_context *ioc;
-
-       ioc = rq_ioc(bio);
-       if (ioc)
-               __blk_mq_sched_assign_ioc(q, rq, bio, ioc);
 }
 
 /*
@@ -107,80 +89,16 @@ static bool blk_mq_sched_restart_hctx(struct blk_mq_hw_ctx *hctx)
        return false;
 }
 
-struct request *blk_mq_sched_get_request(struct request_queue *q,
-                                        struct bio *bio,
-                                        unsigned int op,
-                                        struct blk_mq_alloc_data *data)
-{
-       struct elevator_queue *e = q->elevator;
-       struct request *rq;
-
-       blk_queue_enter_live(q);
-       data->q = q;
-       if (likely(!data->ctx))
-               data->ctx = blk_mq_get_ctx(q);
-       if (likely(!data->hctx))
-               data->hctx = blk_mq_map_queue(q, data->ctx->cpu);
-
-       if (e) {
-               data->flags |= BLK_MQ_REQ_INTERNAL;
-
-               /*
-                * Flush requests are special and go directly to the
-                * dispatch list.
-                */
-               if (!op_is_flush(op) && e->type->ops.mq.get_request) {
-                       rq = e->type->ops.mq.get_request(q, op, data);
-                       if (rq)
-                               rq->rq_flags |= RQF_QUEUED;
-               } else
-                       rq = __blk_mq_alloc_request(data, op);
-       } else {
-               rq = __blk_mq_alloc_request(data, op);
-       }
-
-       if (rq) {
-               if (!op_is_flush(op)) {
-                       rq->elv.icq = NULL;
-                       if (e && e->type->icq_cache)
-                               blk_mq_sched_assign_ioc(q, rq, bio);
-               }
-               data->hctx->queued++;
-               return rq;
-       }
-
-       blk_queue_exit(q);
-       return NULL;
-}
-
-void blk_mq_sched_put_request(struct request *rq)
-{
-       struct request_queue *q = rq->q;
-       struct elevator_queue *e = q->elevator;
-
-       if (rq->rq_flags & RQF_ELVPRIV) {
-               blk_mq_sched_put_rq_priv(rq->q, rq);
-               if (rq->elv.icq) {
-                       put_io_context(rq->elv.icq->ioc);
-                       rq->elv.icq = NULL;
-               }
-       }
-
-       if ((rq->rq_flags & RQF_QUEUED) && e && e->type->ops.mq.put_request)
-               e->type->ops.mq.put_request(rq);
-       else
-               blk_mq_finish_request(rq);
-}
-
 void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
 {
        struct request_queue *q = hctx->queue;
        struct elevator_queue *e = q->elevator;
        const bool has_sched_dispatch = e && e->type->ops.mq.dispatch_request;
-       bool did_work = false;
+       bool do_sched_dispatch = true;
        LIST_HEAD(rq_list);
 
-       if (unlikely(blk_mq_hctx_stopped(hctx)))
+       /* RCU or SRCU read lock is needed before checking quiesced flag */
+       if (unlikely(blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(q)))
                return;
 
        hctx->run++;
@@ -207,18 +125,18 @@ void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
         */
        if (!list_empty(&rq_list)) {
                blk_mq_sched_mark_restart_hctx(hctx);
-               did_work = blk_mq_dispatch_rq_list(q, &rq_list);
+               do_sched_dispatch = blk_mq_dispatch_rq_list(q, &rq_list);
        } else if (!has_sched_dispatch) {
                blk_mq_flush_busy_ctxs(hctx, &rq_list);
                blk_mq_dispatch_rq_list(q, &rq_list);
        }
 
        /*
-        * We want to dispatch from the scheduler if we had no work left
-        * on the dispatch list, OR if we did have work but weren't able
-        * to make progress.
+        * We want to dispatch from the scheduler if there was nothing
+        * on the dispatch list or we were able to dispatch from the
+        * dispatch list.
         */
-       if (!did_work && has_sched_dispatch) {
+       if (do_sched_dispatch && has_sched_dispatch) {
                do {
                        struct request *rq;
 
@@ -260,19 +178,74 @@ bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
 }
 EXPORT_SYMBOL_GPL(blk_mq_sched_try_merge);
 
+/*
+ * Reverse check our software queue for entries that we could potentially
+ * merge with. Currently includes a hand-wavy stop count of 8, to not spend
+ * too much time checking for merges.
+ */
+static bool blk_mq_attempt_merge(struct request_queue *q,
+                                struct blk_mq_ctx *ctx, struct bio *bio)
+{
+       struct request *rq;
+       int checked = 8;
+
+       lockdep_assert_held(&ctx->lock);
+
+       list_for_each_entry_reverse(rq, &ctx->rq_list, queuelist) {
+               bool merged = false;
+
+               if (!checked--)
+                       break;
+
+               if (!blk_rq_merge_ok(rq, bio))
+                       continue;
+
+               switch (blk_try_merge(rq, bio)) {
+               case ELEVATOR_BACK_MERGE:
+                       if (blk_mq_sched_allow_merge(q, rq, bio))
+                               merged = bio_attempt_back_merge(q, rq, bio);
+                       break;
+               case ELEVATOR_FRONT_MERGE:
+                       if (blk_mq_sched_allow_merge(q, rq, bio))
+                               merged = bio_attempt_front_merge(q, rq, bio);
+                       break;
+               case ELEVATOR_DISCARD_MERGE:
+                       merged = bio_attempt_discard_merge(q, rq, bio);
+                       break;
+               default:
+                       continue;
+               }
+
+               if (merged)
+                       ctx->rq_merged++;
+               return merged;
+       }
+
+       return false;
+}
+
 bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio)
 {
        struct elevator_queue *e = q->elevator;
+       struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
+       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
+       bool ret = false;
 
-       if (e->type->ops.mq.bio_merge) {
-               struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
-               struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
-
+       if (e && e->type->ops.mq.bio_merge) {
                blk_mq_put_ctx(ctx);
                return e->type->ops.mq.bio_merge(hctx, bio);
        }
 
-       return false;
+       if ((hctx->flags & BLK_MQ_F_SHOULD_MERGE) &&
+                       !list_empty_careful(&ctx->rq_list)) {
+               /* default per sw-queue merge */
+               spin_lock(&ctx->lock);
+               ret = blk_mq_attempt_merge(q, ctx, bio);
+               spin_unlock(&ctx->lock);
+       }
+
+       blk_mq_put_ctx(ctx);
+       return ret;
 }
 
 bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq)
@@ -543,10 +516,12 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
        }
 
        /*
-        * Default to 256, since we don't split into sync/async like the
-        * old code did. Additionally, this is a per-hw queue depth.
+        * Default to double of smaller one between hw queue_depth and 128,
+        * since we don't split into sync/async like the old code did.
+        * Additionally, this is a per-hw queue depth.
         */
-       q->nr_requests = 2 * BLKDEV_MAX_RQ;
+       q->nr_requests = 2 * min_t(unsigned int, q->tag_set->queue_depth,
+                                  BLKDEV_MAX_RQ);
 
        queue_for_each_hw_ctx(q, hctx, i) {
                ret = blk_mq_sched_alloc_tags(q, hctx, i);