Skip to content

Commit

Permalink
Merge tag 'nvme-5.14-2021-07-15' of git://git.infradead.org/nvme into…
Browse files Browse the repository at this point in the history
… block-5.14

Pull NVMe fixes from Christoph:

"nvme fixes for Linux 5.14

 - fix various races in nvme-pci when shutting down just after probing
   (Casey Chen)
 - fix a net_device leak in nvme-tcp (Prabhakar Kushwaha)"

* tag 'nvme-5.14-2021-07-15' of git://git.infradead.org/nvme:
  nvme-pci: do not call nvme_dev_remove_admin from nvme_remove
  nvme-pci: fix multiple races in nvme_setup_io_queues
  nvme-tcp: use __dev_get_by_name instead dev_get_by_name for OPT_HOST_IFACE
  • Loading branch information
axboe committed Jul 15, 2021
2 parents 16ad3db + 251ef6f commit a347c15
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 12 deletions.
67 changes: 58 additions & 9 deletions drivers/nvme/host/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1554,6 +1554,28 @@ static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid)
wmb(); /* ensure the first interrupt sees the initialization */
}

/*
* Try getting shutdown_lock while setting up IO queues.
*/
static int nvme_setup_io_queues_trylock(struct nvme_dev *dev)
{
/*
* Give up if the lock is being held by nvme_dev_disable.
*/
if (!mutex_trylock(&dev->shutdown_lock))
return -ENODEV;

/*
* Controller is in wrong state, fail early.
*/
if (dev->ctrl.state != NVME_CTRL_CONNECTING) {
mutex_unlock(&dev->shutdown_lock);
return -ENODEV;
}

return 0;
}

static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)
{
struct nvme_dev *dev = nvmeq->dev;
Expand Down Expand Up @@ -1582,19 +1604,24 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)
goto release_cq;

nvmeq->cq_vector = vector;
nvme_init_queue(nvmeq, qid);

result = nvme_setup_io_queues_trylock(dev);
if (result)
return result;
nvme_init_queue(nvmeq, qid);
if (!polled) {
result = queue_request_irq(nvmeq);
if (result < 0)
goto release_sq;
}

set_bit(NVMEQ_ENABLED, &nvmeq->flags);
mutex_unlock(&dev->shutdown_lock);
return result;

release_sq:
dev->online_queues--;
mutex_unlock(&dev->shutdown_lock);
adapter_delete_sq(dev, qid);
release_cq:
adapter_delete_cq(dev, qid);
Expand Down Expand Up @@ -2167,7 +2194,18 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (nr_io_queues == 0)
return 0;

clear_bit(NVMEQ_ENABLED, &adminq->flags);
/*
* Free IRQ resources as soon as NVMEQ_ENABLED bit transitions
* from set to unset. If there is a window to it is truely freed,
* pci_free_irq_vectors() jumping into this window will crash.
* And take lock to avoid racing with pci_free_irq_vectors() in
* nvme_dev_disable() path.
*/
result = nvme_setup_io_queues_trylock(dev);
if (result)
return result;
if (test_and_clear_bit(NVMEQ_ENABLED, &adminq->flags))
pci_free_irq(pdev, 0, adminq);

if (dev->cmb_use_sqes) {
result = nvme_cmb_qdepth(dev, nr_io_queues,
Expand All @@ -2183,14 +2221,17 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
result = nvme_remap_bar(dev, size);
if (!result)
break;
if (!--nr_io_queues)
return -ENOMEM;
if (!--nr_io_queues) {
result = -ENOMEM;
goto out_unlock;
}
} while (1);
adminq->q_db = dev->dbs;

retry:
/* Deregister the admin queue's interrupt */
pci_free_irq(pdev, 0, adminq);
if (test_and_clear_bit(NVMEQ_ENABLED, &adminq->flags))
pci_free_irq(pdev, 0, adminq);

/*
* If we enable msix early due to not intx, disable it again before
Expand All @@ -2199,8 +2240,10 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
pci_free_irq_vectors(pdev);

result = nvme_setup_irqs(dev, nr_io_queues);
if (result <= 0)
return -EIO;
if (result <= 0) {
result = -EIO;
goto out_unlock;
}

dev->num_vecs = result;
result = max(result - 1, 1);
Expand All @@ -2214,8 +2257,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
*/
result = queue_request_irq(adminq);
if (result)
return result;
goto out_unlock;
set_bit(NVMEQ_ENABLED, &adminq->flags);
mutex_unlock(&dev->shutdown_lock);

result = nvme_create_io_queues(dev);
if (result || dev->online_queues < 2)
Expand All @@ -2224,6 +2268,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (dev->online_queues - 1 < dev->max_qid) {
nr_io_queues = dev->online_queues - 1;
nvme_disable_io_queues(dev);
result = nvme_setup_io_queues_trylock(dev);
if (result)
return result;
nvme_suspend_io_queues(dev);
goto retry;
}
Expand All @@ -2232,6 +2279,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
dev->io_queues[HCTX_TYPE_READ],
dev->io_queues[HCTX_TYPE_POLL]);
return 0;
out_unlock:
mutex_unlock(&dev->shutdown_lock);
return result;
}

static void nvme_del_queue_end(struct request *req, blk_status_t error)
Expand Down Expand Up @@ -2962,7 +3012,6 @@ static void nvme_remove(struct pci_dev *pdev)
if (!pci_device_is_present(pdev)) {
nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DEAD);
nvme_dev_disable(dev, true);
nvme_dev_remove_admin(dev);
}

flush_work(&dev->ctrl.reset_work);
Expand Down
4 changes: 1 addition & 3 deletions drivers/nvme/host/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ struct nvme_tcp_ctrl {
struct blk_mq_tag_set admin_tag_set;
struct sockaddr_storage addr;
struct sockaddr_storage src_addr;
struct net_device *ndev;
struct nvme_ctrl ctrl;

struct work_struct err_work;
Expand Down Expand Up @@ -2533,8 +2532,7 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
}

if (opts->mask & NVMF_OPT_HOST_IFACE) {
ctrl->ndev = dev_get_by_name(&init_net, opts->host_iface);
if (!ctrl->ndev) {
if (!__dev_get_by_name(&init_net, opts->host_iface)) {
pr_err("invalid interface passed: %s\n",
opts->host_iface);
ret = -ENODEV;
Expand Down

0 comments on commit a347c15

Please sign in to comment.