Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[linux-2.6-microblaze.git] / block / blk-mq-tag.c
index 2a37731..86f8734 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include "blk.h"
 #include "blk-mq.h"
+#include "blk-mq-sched.h"
 #include "blk-mq-tag.h"
 
 /*
@@ -199,6 +200,20 @@ struct bt_iter_data {
        bool reserved;
 };
 
+static struct request *blk_mq_find_and_get_req(struct blk_mq_tags *tags,
+               unsigned int bitnr)
+{
+       struct request *rq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tags->lock, flags);
+       rq = tags->rqs[bitnr];
+       if (!rq || !refcount_inc_not_zero(&rq->ref))
+               rq = NULL;
+       spin_unlock_irqrestore(&tags->lock, flags);
+       return rq;
+}
+
 static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
 {
        struct bt_iter_data *iter_data = data;
@@ -206,18 +221,22 @@ static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
        struct blk_mq_tags *tags = hctx->tags;
        bool reserved = iter_data->reserved;
        struct request *rq;
+       bool ret = true;
 
        if (!reserved)
                bitnr += tags->nr_reserved_tags;
-       rq = tags->rqs[bitnr];
-
        /*
         * We can hit rq == NULL here, because the tagging functions
         * test and set the bit before assigning ->rqs[].
         */
-       if (rq && rq->q == hctx->queue && rq->mq_hctx == hctx)
-               return iter_data->fn(hctx, rq, iter_data->data, reserved);
-       return true;
+       rq = blk_mq_find_and_get_req(tags, bitnr);
+       if (!rq)
+               return true;
+
+       if (rq->q == hctx->queue && rq->mq_hctx == hctx)
+               ret = iter_data->fn(hctx, rq, iter_data->data, reserved);
+       blk_mq_put_rq_ref(rq);
+       return ret;
 }
 
 /**
@@ -264,6 +283,8 @@ static bool bt_tags_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
        struct blk_mq_tags *tags = iter_data->tags;
        bool reserved = iter_data->flags & BT_TAG_ITER_RESERVED;
        struct request *rq;
+       bool ret = true;
+       bool iter_static_rqs = !!(iter_data->flags & BT_TAG_ITER_STATIC_RQS);
 
        if (!reserved)
                bitnr += tags->nr_reserved_tags;
@@ -272,16 +293,19 @@ static bool bt_tags_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
         * We can hit rq == NULL here, because the tagging functions
         * test and set the bit before assigning ->rqs[].
         */
-       if (iter_data->flags & BT_TAG_ITER_STATIC_RQS)
+       if (iter_static_rqs)
                rq = tags->static_rqs[bitnr];
        else
-               rq = tags->rqs[bitnr];
+               rq = blk_mq_find_and_get_req(tags, bitnr);
        if (!rq)
                return true;
-       if ((iter_data->flags & BT_TAG_ITER_STARTED) &&
-           !blk_mq_request_started(rq))
-               return true;
-       return iter_data->fn(rq, iter_data->data, reserved);
+
+       if (!(iter_data->flags & BT_TAG_ITER_STARTED) ||
+           blk_mq_request_started(rq))
+               ret = iter_data->fn(rq, iter_data->data, reserved);
+       if (!iter_static_rqs)
+               blk_mq_put_rq_ref(rq);
+       return ret;
 }
 
 /**
@@ -348,6 +372,9 @@ void blk_mq_all_tag_iter(struct blk_mq_tags *tags, busy_tag_iter_fn *fn,
  *             indicates whether or not @rq is a reserved request. Return
  *             true to continue iterating tags, false to stop.
  * @priv:      Will be passed as second argument to @fn.
+ *
+ * We grab one request reference before calling @fn and release it after
+ * @fn returns.
  */
 void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset,
                busy_tag_iter_fn *fn, void *priv)
@@ -445,39 +472,54 @@ static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth,
                                       node);
 }
 
-static int blk_mq_init_bitmap_tags(struct blk_mq_tags *tags,
-                                  int node, int alloc_policy)
+int blk_mq_init_bitmaps(struct sbitmap_queue *bitmap_tags,
+                       struct sbitmap_queue *breserved_tags,
+                       unsigned int queue_depth, unsigned int reserved,
+                       int node, int alloc_policy)
 {
-       unsigned int depth = tags->nr_tags - tags->nr_reserved_tags;
+       unsigned int depth = queue_depth - reserved;
        bool round_robin = alloc_policy == BLK_TAG_ALLOC_RR;
 
-       if (bt_alloc(&tags->__bitmap_tags, depth, round_robin, node))
+       if (bt_alloc(bitmap_tags, depth, round_robin, node))
                return -ENOMEM;
-       if (bt_alloc(&tags->__breserved_tags, tags->nr_reserved_tags,
-                    round_robin, node))
+       if (bt_alloc(breserved_tags, reserved, round_robin, node))
                goto free_bitmap_tags;
 
+       return 0;
+
+free_bitmap_tags:
+       sbitmap_queue_free(bitmap_tags);
+       return -ENOMEM;
+}
+
+static int blk_mq_init_bitmap_tags(struct blk_mq_tags *tags,
+                                  int node, int alloc_policy)
+{
+       int ret;
+
+       ret = blk_mq_init_bitmaps(&tags->__bitmap_tags,
+                                 &tags->__breserved_tags,
+                                 tags->nr_tags, tags->nr_reserved_tags,
+                                 node, alloc_policy);
+       if (ret)
+               return ret;
+
        tags->bitmap_tags = &tags->__bitmap_tags;
        tags->breserved_tags = &tags->__breserved_tags;
 
        return 0;
-free_bitmap_tags:
-       sbitmap_queue_free(&tags->__bitmap_tags);
-       return -ENOMEM;
 }
 
-int blk_mq_init_shared_sbitmap(struct blk_mq_tag_set *set, unsigned int flags)
+int blk_mq_init_shared_sbitmap(struct blk_mq_tag_set *set)
 {
-       unsigned int depth = set->queue_depth - set->reserved_tags;
        int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(set->flags);
-       bool round_robin = alloc_policy == BLK_TAG_ALLOC_RR;
-       int i, node = set->numa_node;
+       int i, ret;
 
-       if (bt_alloc(&set->__bitmap_tags, depth, round_robin, node))
-               return -ENOMEM;
-       if (bt_alloc(&set->__breserved_tags, set->reserved_tags,
-                    round_robin, node))
-               goto free_bitmap_tags;
+       ret = blk_mq_init_bitmaps(&set->__bitmap_tags, &set->__breserved_tags,
+                                 set->queue_depth, set->reserved_tags,
+                                 set->numa_node, alloc_policy);
+       if (ret)
+               return ret;
 
        for (i = 0; i < set->nr_hw_queues; i++) {
                struct blk_mq_tags *tags = set->tags[i];
@@ -487,9 +529,6 @@ int blk_mq_init_shared_sbitmap(struct blk_mq_tag_set *set, unsigned int flags)
        }
 
        return 0;
-free_bitmap_tags:
-       sbitmap_queue_free(&set->__bitmap_tags);
-       return -ENOMEM;
 }
 
 void blk_mq_exit_shared_sbitmap(struct blk_mq_tag_set *set)
@@ -516,6 +555,7 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
 
        tags->nr_tags = total_tags;
        tags->nr_reserved_tags = reserved_tags;
+       spin_lock_init(&tags->lock);
 
        if (blk_mq_is_sbitmap_shared(flags))
                return tags;
@@ -551,8 +591,6 @@ int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx,
         */
        if (tdepth > tags->nr_tags) {
                struct blk_mq_tag_set *set = hctx->queue->tag_set;
-               /* Only sched tags can grow, so clear HCTX_SHARED flag  */
-               unsigned int flags = set->flags & ~BLK_MQ_F_TAG_HCTX_SHARED;
                struct blk_mq_tags *new;
                bool ret;
 
@@ -563,21 +601,21 @@ int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx,
                 * We need some sort of upper limit, set it high enough that
                 * no valid use cases should require more.
                 */
-               if (tdepth > 16 * BLKDEV_MAX_RQ)
+               if (tdepth > MAX_SCHED_RQ)
                        return -EINVAL;
 
                new = blk_mq_alloc_rq_map(set, hctx->queue_num, tdepth,
-                               tags->nr_reserved_tags, flags);
+                               tags->nr_reserved_tags, set->flags);
                if (!new)
                        return -ENOMEM;
                ret = blk_mq_alloc_rqs(set, new, hctx->queue_num, tdepth);
                if (ret) {
-                       blk_mq_free_rq_map(new, flags);
+                       blk_mq_free_rq_map(new, set->flags);
                        return -ENOMEM;
                }
 
                blk_mq_free_rqs(set, *tagsptr, hctx->queue_num);
-               blk_mq_free_rq_map(*tagsptr, flags);
+               blk_mq_free_rq_map(*tagsptr, set->flags);
                *tagsptr = new;
        } else {
                /*