Merge tag 'rproc-v4.15' of git://github.com/andersson/remoteproc
[linux-2.6-block.git] / block / blk-mq.c
index e21876778cecd0a3d647f912bd19ccf22aea2b67..11097477eeab6591088ca817d4690535e114e699 100644 (file)
@@ -61,10 +61,10 @@ static int blk_mq_poll_stats_bkt(const struct request *rq)
 /*
  * Check if any of the ctx's have pending work in this hardware queue
  */
-bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx)
+static bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx)
 {
-       return sbitmap_any_bit_set(&hctx->ctx_map) ||
-                       !list_empty_careful(&hctx->dispatch) ||
+       return !list_empty_careful(&hctx->dispatch) ||
+               sbitmap_any_bit_set(&hctx->ctx_map) ||
                        blk_mq_sched_has_work(hctx);
 }
 
@@ -383,13 +383,13 @@ static struct request *blk_mq_get_request(struct request_queue *q,
 }
 
 struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
-               unsigned int flags)
+               blk_mq_req_flags_t flags)
 {
        struct blk_mq_alloc_data alloc_data = { .flags = flags };
        struct request *rq;
        int ret;
 
-       ret = blk_queue_enter(q, flags & BLK_MQ_REQ_NOWAIT);
+       ret = blk_queue_enter(q, flags);
        if (ret)
                return ERR_PTR(ret);
 
@@ -409,7 +409,7 @@ struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
 EXPORT_SYMBOL(blk_mq_alloc_request);
 
 struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
-               unsigned int op, unsigned int flags, unsigned int hctx_idx)
+       unsigned int op, blk_mq_req_flags_t flags, unsigned int hctx_idx)
 {
        struct blk_mq_alloc_data alloc_data = { .flags = flags };
        struct request *rq;
@@ -428,7 +428,7 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
        if (hctx_idx >= q->nr_hw_queues)
                return ERR_PTR(-EIO);
 
-       ret = blk_queue_enter(q, true);
+       ret = blk_queue_enter(q, flags);
        if (ret)
                return ERR_PTR(ret);
 
@@ -707,7 +707,7 @@ void blk_mq_add_to_requeue_list(struct request *rq, bool at_head,
 
        /*
         * We abuse this flag that is otherwise used by the I/O scheduler to
-        * request head insertation from the workqueue.
+        * request head insertion from the workqueue.
         */
        BUG_ON(rq->rq_flags & RQF_SOFTBARRIER);
 
@@ -1006,44 +1006,68 @@ static int blk_mq_dispatch_wake(wait_queue_entry_t *wait, unsigned mode,
        return 1;
 }
 
-static bool blk_mq_dispatch_wait_add(struct blk_mq_hw_ctx **hctx,
-                                    struct request *rq)
+/*
+ * Mark us waiting for a tag. For shared tags, this involves hooking us into
+ * the tag wakeups. For non-shared tags, we can simply mark us nedeing a
+ * restart. For both caes, take care to check the condition again after
+ * marking us as waiting.
+ */
+static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx **hctx,
+                                struct request *rq)
 {
        struct blk_mq_hw_ctx *this_hctx = *hctx;
-       wait_queue_entry_t *wait = &this_hctx->dispatch_wait;
+       bool shared_tags = (this_hctx->flags & BLK_MQ_F_TAG_SHARED) != 0;
        struct sbq_wait_state *ws;
+       wait_queue_entry_t *wait;
+       bool ret;
 
-       if (!list_empty_careful(&wait->entry))
-               return false;
+       if (!shared_tags) {
+               if (!test_bit(BLK_MQ_S_SCHED_RESTART, &this_hctx->state))
+                       set_bit(BLK_MQ_S_SCHED_RESTART, &this_hctx->state);
+       } else {
+               wait = &this_hctx->dispatch_wait;
+               if (!list_empty_careful(&wait->entry))
+                       return false;
 
-       spin_lock(&this_hctx->lock);
-       if (!list_empty(&wait->entry)) {
-               spin_unlock(&this_hctx->lock);
-               return false;
-       }
+               spin_lock(&this_hctx->lock);
+               if (!list_empty(&wait->entry)) {
+                       spin_unlock(&this_hctx->lock);
+                       return false;
+               }
 
-       ws = bt_wait_ptr(&this_hctx->tags->bitmap_tags, this_hctx);
-       add_wait_queue(&ws->wait, wait);
+               ws = bt_wait_ptr(&this_hctx->tags->bitmap_tags, this_hctx);
+               add_wait_queue(&ws->wait, wait);
+       }
 
        /*
         * It's possible that a tag was freed in the window between the
         * allocation failure and adding the hardware queue to the wait
         * queue.
         */
-       if (!blk_mq_get_driver_tag(rq, hctx, false)) {
+       ret = blk_mq_get_driver_tag(rq, hctx, false);
+
+       if (!shared_tags) {
+               /*
+                * Don't clear RESTART here, someone else could have set it.
+                * At most this will cost an extra queue run.
+                */
+               return ret;
+       } else {
+               if (!ret) {
+                       spin_unlock(&this_hctx->lock);
+                       return false;
+               }
+
+               /*
+                * We got a tag, remove ourselves from the wait queue to ensure
+                * someone else gets the wakeup.
+                */
+               spin_lock_irq(&ws->wait.lock);
+               list_del_init(&wait->entry);
+               spin_unlock_irq(&ws->wait.lock);
                spin_unlock(&this_hctx->lock);
-               return false;
+               return true;
        }
-
-       /*
-        * We got a tag, remove ourselves from the wait queue to ensure
-        * someone else gets the wakeup.
-        */
-       spin_lock_irq(&ws->wait.lock);
-       list_del_init(&wait->entry);
-       spin_unlock_irq(&ws->wait.lock);
-       spin_unlock(&this_hctx->lock);
-       return true;
 }
 
 bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
@@ -1076,10 +1100,15 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
                         * before we add this entry back on the dispatch list,
                         * we'll re-run it below.
                         */
-                       if (!blk_mq_dispatch_wait_add(&hctx, rq)) {
+                       if (!blk_mq_mark_tag_wait(&hctx, rq)) {
                                if (got_budget)
                                        blk_mq_put_dispatch_budget(hctx);
-                               no_tag = true;
+                               /*
+                                * For non-shared tags, the RESTART check
+                                * will suffice.
+                                */
+                               if (hctx->flags & BLK_MQ_F_TAG_SHARED)
+                                       no_tag = true;
                                break;
                        }
                }
@@ -1108,7 +1137,8 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
                if (ret == BLK_STS_RESOURCE) {
                        /*
                         * If an I/O scheduler has been configured and we got a
-                        * driver tag for the next request already, free it again.
+                        * driver tag for the next request already, free it
+                        * again.
                         */
                        if (!list_empty(list)) {
                                nxt = list_first_entry(list, struct request, queuelist);
@@ -1253,9 +1283,14 @@ void blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs)
 }
 EXPORT_SYMBOL(blk_mq_delay_run_hw_queue);
 
-void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
+bool blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
 {
-       __blk_mq_delay_run_hw_queue(hctx, async, 0);
+       if (blk_mq_hctx_has_pending(hctx)) {
+               __blk_mq_delay_run_hw_queue(hctx, async, 0);
+               return true;
+       }
+
+       return false;
 }
 EXPORT_SYMBOL(blk_mq_run_hw_queue);
 
@@ -1265,8 +1300,7 @@ void blk_mq_run_hw_queues(struct request_queue *q, bool async)
        int i;
 
        queue_for_each_hw_ctx(q, hctx, i) {
-               if (!blk_mq_hctx_has_pending(hctx) ||
-                   blk_mq_hctx_stopped(hctx))
+               if (blk_mq_hctx_stopped(hctx))
                        continue;
 
                blk_mq_run_hw_queue(hctx, async);
@@ -2013,7 +2047,7 @@ static int blk_mq_init_hctx(struct request_queue *q,
         * Allocate space for all possible cpus to avoid allocation at
         * runtime
         */
-       hctx->ctxs = kmalloc_node(nr_cpu_ids * sizeof(void *),
+       hctx->ctxs = kmalloc_array_node(nr_cpu_ids, sizeof(void *),
                                        GFP_KERNEL, node);
        if (!hctx->ctxs)
                goto unregister_cpu_notifier;
@@ -2266,8 +2300,11 @@ static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
 
        mutex_lock(&set->tag_list_lock);
 
-       /* Check to see if we're transitioning to shared (from 1 to 2 queues). */
-       if (!list_empty(&set->tag_list) && !(set->flags & BLK_MQ_F_TAG_SHARED)) {
+       /*
+        * Check to see if we're transitioning to shared (from 1 to 2 queues).
+        */
+       if (!list_empty(&set->tag_list) &&
+           !(set->flags & BLK_MQ_F_TAG_SHARED)) {
                set->flags |= BLK_MQ_F_TAG_SHARED;
                /* update existing queue */
                blk_mq_update_tag_set_depth(set, true);
@@ -2499,10 +2536,9 @@ static void blk_mq_queue_reinit(struct request_queue *q)
 
        /*
         * redo blk_mq_init_cpu_queues and blk_mq_init_hw_queues. FIXME: maybe
-        * we should change hctx numa_node according to new topology (this
-        * involves free and re-allocate memory, worthy doing?)
+        * we should change hctx numa_node according to the new topology (this
+        * involves freeing and re-allocating memory, worth doing?)
         */
-
        blk_mq_map_swqueue(q);
 
        blk_mq_sysfs_register(q);