The fact that blk_mq_destroy_queue also drops a queue reference leads
to various places having to grab an extra reference.  Move the call to
blk_put_queue into the callers to allow removing the extra references.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20221018135720.670094-2-hch@lst.de
[axboe: fix fabrics_q vs admin_q conflict in nvme core.c]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
        blk_sync_queue(q);
        blk_mq_cancel_work_sync(q);
        blk_mq_exit_queue(q);
-
-       /* @q is and will stay empty, shutdown and put */
-       blk_put_queue(q);
 }
 EXPORT_SYMBOL(blk_mq_destroy_queue);
 
        disk = __alloc_disk_node(q, set->numa_node, lkclass);
        if (!disk) {
                blk_mq_destroy_queue(q);
+               blk_put_queue(q);
                return ERR_PTR(-ENOMEM);
        }
        set_bit(GD_OWNS_QUEUE, &disk->state);
 
 
                bsg_unregister_queue(bset->bd);
                blk_mq_destroy_queue(q);
+               blk_put_queue(q);
                blk_mq_free_tag_set(&bset->tag_set);
                kfree(bset);
        }
        return q;
 out_cleanup_queue:
        blk_mq_destroy_queue(q);
+       blk_put_queue(q);
 out_queue:
        blk_mq_free_tag_set(set);
 out_tag_set:
 
        if (!blk_get_queue(anv->ctrl.admin_q)) {
                nvme_start_admin_queue(&anv->ctrl);
                blk_mq_destroy_queue(anv->ctrl.admin_q);
+               blk_put_queue(anv->ctrl.admin_q);
                anv->ctrl.admin_q = NULL;
                ret = -ENODEV;
                goto put_dev;
 
 
 out_cleanup_admin_q:
        blk_mq_destroy_queue(ctrl->admin_q);
+       blk_put_queue(ctrl->admin_q);
 out_free_tagset:
        blk_mq_free_tag_set(ctrl->admin_tagset);
        return ret;
 void nvme_remove_admin_tag_set(struct nvme_ctrl *ctrl)
 {
        blk_mq_destroy_queue(ctrl->admin_q);
-       if (ctrl->ops->flags & NVME_F_FABRICS)
+       blk_put_queue(ctrl->admin_q);
+       if (ctrl->ops->flags & NVME_F_FABRICS) {
                blk_mq_destroy_queue(ctrl->fabrics_q);
+               blk_put_queue(ctrl->fabrics_q);
+       }
        blk_mq_free_tag_set(ctrl->admin_tagset);
 }
 EXPORT_SYMBOL_GPL(nvme_remove_admin_tag_set);
 
 void nvme_remove_io_tag_set(struct nvme_ctrl *ctrl)
 {
-       if (ctrl->ops->flags & NVME_F_FABRICS)
+       if (ctrl->ops->flags & NVME_F_FABRICS) {
                blk_mq_destroy_queue(ctrl->connect_q);
+               blk_put_queue(ctrl->connect_q);
+       }
        blk_mq_free_tag_set(ctrl->tagset);
 }
 EXPORT_SYMBOL_GPL(nvme_remove_io_tag_set);
 
                 */
                nvme_start_admin_queue(&dev->ctrl);
                blk_mq_destroy_queue(dev->ctrl.admin_q);
+               blk_put_queue(dev->ctrl.admin_q);
                blk_mq_free_tag_set(&dev->admin_tagset);
        }
 }
 
        mutex_unlock(&sdev->state_mutex);
 
        blk_mq_destroy_queue(sdev->request_queue);
+       blk_put_queue(sdev->request_queue);
        kref_put(&sdev->host->tagset_refcnt, scsi_mq_free_tags);
        cancel_work_sync(&sdev->requeue_work);
 
 
        ufshpb_remove(hba);
        ufs_sysfs_remove_nodes(hba->dev);
        blk_mq_destroy_queue(hba->tmf_queue);
+       blk_put_queue(hba->tmf_queue);
        blk_mq_free_tag_set(&hba->tmf_tag_set);
        scsi_remove_host(hba->host);
        /* disable interrupts */
 
 free_tmf_queue:
        blk_mq_destroy_queue(hba->tmf_queue);
+       blk_put_queue(hba->tmf_queue);
 free_tmf_tag_set:
        blk_mq_free_tag_set(&hba->tmf_tag_set);
 out_remove_scsi_host: