diff options
author | Tejun Heo <tj@kernel.org> | 2014-03-07 10:24:49 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-03-07 10:24:49 -0500 |
commit | 9ca9737444f1a8602f74b85018d881e7e54b5bd1 (patch) | |
tree | 925cd29c17b2c2d5e68d1804e798f41d2301a501 | |
parent | 77fa83cf7478202fac1520ca082ab8f9658d63b4 (diff) |
nvme: don't use PREPARE_WORK
PREPARE_[DELAYED_]WORK() are being phased out. They have few users
and a nasty surprise in terms of reentrancy guarantee as workqueue
considers work items to be different if they don't have the same work
function.
nvme_dev->reset_work is multiplexed with multiple work functions.
Introduce nvme_reset_workfn() which invokes nvme_dev->reset_workfn and
always use it as the work function and update the users to set the
->reset_workfn field instead of overriding the work function using
PREPARE_WORK().
It would probably be best to route this with other related updates
through the workqueue tree.
Compile tested.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Matthew Wilcox <willy@linux.intel.com>
Cc: linux-nvme@lists.infradead.org
-rw-r--r-- | drivers/block/nvme-core.c | 18 | ||||
-rw-r--r-- | include/linux/nvme.h | 1 |
2 files changed, 13 insertions, 6 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 51824d1f23ea..8459e4e7c719 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c | |||
@@ -993,7 +993,7 @@ static void nvme_abort_cmd(int cmdid, struct nvme_queue *nvmeq) | |||
993 | dev_warn(&dev->pci_dev->dev, | 993 | dev_warn(&dev->pci_dev->dev, |
994 | "I/O %d QID %d timeout, reset controller\n", cmdid, | 994 | "I/O %d QID %d timeout, reset controller\n", cmdid, |
995 | nvmeq->qid); | 995 | nvmeq->qid); |
996 | PREPARE_WORK(&dev->reset_work, nvme_reset_failed_dev); | 996 | dev->reset_workfn = nvme_reset_failed_dev; |
997 | queue_work(nvme_workq, &dev->reset_work); | 997 | queue_work(nvme_workq, &dev->reset_work); |
998 | return; | 998 | return; |
999 | } | 999 | } |
@@ -1696,8 +1696,7 @@ static int nvme_kthread(void *data) | |||
1696 | list_del_init(&dev->node); | 1696 | list_del_init(&dev->node); |
1697 | dev_warn(&dev->pci_dev->dev, | 1697 | dev_warn(&dev->pci_dev->dev, |
1698 | "Failed status, reset controller\n"); | 1698 | "Failed status, reset controller\n"); |
1699 | PREPARE_WORK(&dev->reset_work, | 1699 | dev->reset_workfn = nvme_reset_failed_dev; |
1700 | nvme_reset_failed_dev); | ||
1701 | queue_work(nvme_workq, &dev->reset_work); | 1700 | queue_work(nvme_workq, &dev->reset_work); |
1702 | continue; | 1701 | continue; |
1703 | } | 1702 | } |
@@ -2406,7 +2405,7 @@ static int nvme_dev_resume(struct nvme_dev *dev) | |||
2406 | return ret; | 2405 | return ret; |
2407 | if (ret == -EBUSY) { | 2406 | if (ret == -EBUSY) { |
2408 | spin_lock(&dev_list_lock); | 2407 | spin_lock(&dev_list_lock); |
2409 | PREPARE_WORK(&dev->reset_work, nvme_remove_disks); | 2408 | dev->reset_workfn = nvme_remove_disks; |
2410 | queue_work(nvme_workq, &dev->reset_work); | 2409 | queue_work(nvme_workq, &dev->reset_work); |
2411 | spin_unlock(&dev_list_lock); | 2410 | spin_unlock(&dev_list_lock); |
2412 | } | 2411 | } |
@@ -2435,6 +2434,12 @@ static void nvme_reset_failed_dev(struct work_struct *ws) | |||
2435 | nvme_dev_reset(dev); | 2434 | nvme_dev_reset(dev); |
2436 | } | 2435 | } |
2437 | 2436 | ||
2437 | static void nvme_reset_workfn(struct work_struct *work) | ||
2438 | { | ||
2439 | struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work); | ||
2440 | dev->reset_workfn(work); | ||
2441 | } | ||
2442 | |||
2438 | static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 2443 | static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
2439 | { | 2444 | { |
2440 | int result = -ENOMEM; | 2445 | int result = -ENOMEM; |
@@ -2453,7 +2458,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2453 | goto free; | 2458 | goto free; |
2454 | 2459 | ||
2455 | INIT_LIST_HEAD(&dev->namespaces); | 2460 | INIT_LIST_HEAD(&dev->namespaces); |
2456 | INIT_WORK(&dev->reset_work, nvme_reset_failed_dev); | 2461 | dev->reset_workfn = nvme_reset_failed_dev; |
2462 | INIT_WORK(&dev->reset_work, nvme_reset_workfn); | ||
2457 | dev->pci_dev = pdev; | 2463 | dev->pci_dev = pdev; |
2458 | pci_set_drvdata(pdev, dev); | 2464 | pci_set_drvdata(pdev, dev); |
2459 | result = nvme_set_instance(dev); | 2465 | result = nvme_set_instance(dev); |
@@ -2553,7 +2559,7 @@ static int nvme_resume(struct device *dev) | |||
2553 | struct nvme_dev *ndev = pci_get_drvdata(pdev); | 2559 | struct nvme_dev *ndev = pci_get_drvdata(pdev); |
2554 | 2560 | ||
2555 | if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) { | 2561 | if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) { |
2556 | PREPARE_WORK(&ndev->reset_work, nvme_reset_failed_dev); | 2562 | ndev->reset_workfn = nvme_reset_failed_dev; |
2557 | queue_work(nvme_workq, &ndev->reset_work); | 2563 | queue_work(nvme_workq, &ndev->reset_work); |
2558 | } | 2564 | } |
2559 | return 0; | 2565 | return 0; |
diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 69ae03f6eb15..6b9aafed225f 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h | |||
@@ -87,6 +87,7 @@ struct nvme_dev { | |||
87 | struct list_head namespaces; | 87 | struct list_head namespaces; |
88 | struct kref kref; | 88 | struct kref kref; |
89 | struct miscdevice miscdev; | 89 | struct miscdevice miscdev; |
90 | work_func_t reset_workfn; | ||
90 | struct work_struct reset_work; | 91 | struct work_struct reset_work; |
91 | char name[12]; | 92 | char name[12]; |
92 | char serial[20]; | 93 | char serial[20]; |