diff options
| author | Roland Dreier <roland@purestorage.com> | 2018-01-11 16:38:15 -0500 |
|---|---|---|
| committer | Sagi Grimberg <sagi@grimberg.me> | 2018-02-12 15:18:14 -0500 |
| commit | 0a34e4668c508cbbc2d5ef2d9710b145e4c0b27d (patch) | |
| tree | 53697e55ea1cfe7236ccac678c0a2ac6b103a9d9 /drivers | |
| parent | c3aedd225f8bcc3b3e61df074bc045b80542b38a (diff) | |
nvme: Don't use a stack buffer for keep-alive command
In nvme_keep_alive() we pass a request with a pointer to an NVMe command on
the stack into blk_execute_rq_nowait(). However, the block layer doesn't
guarantee that the request is fully queued before blk_execute_rq_nowait()
returns. If not, and the request is queued after nvme_keep_alive() returns,
then we'll end up using stack memory that might have been overwritten to
form the NVMe command we pass to hardware.
Fix this by keeping a special command struct in the nvme_ctrl struct right
next to the delayed work struct used for keep-alives.
Signed-off-by: Roland Dreier <roland@purestorage.com>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/nvme/host/core.c | 8 | ||||
| -rw-r--r-- | drivers/nvme/host/nvme.h | 1 |
2 files changed, 4 insertions, 5 deletions
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 2fd8688cfa47..6d0490b477c9 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c | |||
| @@ -796,13 +796,9 @@ static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status) | |||
| 796 | 796 | ||
| 797 | static int nvme_keep_alive(struct nvme_ctrl *ctrl) | 797 | static int nvme_keep_alive(struct nvme_ctrl *ctrl) |
| 798 | { | 798 | { |
| 799 | struct nvme_command c; | ||
| 800 | struct request *rq; | 799 | struct request *rq; |
| 801 | 800 | ||
| 802 | memset(&c, 0, sizeof(c)); | 801 | rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd, BLK_MQ_REQ_RESERVED, |
| 803 | c.common.opcode = nvme_admin_keep_alive; | ||
| 804 | |||
| 805 | rq = nvme_alloc_request(ctrl->admin_q, &c, BLK_MQ_REQ_RESERVED, | ||
| 806 | NVME_QID_ANY); | 802 | NVME_QID_ANY); |
| 807 | if (IS_ERR(rq)) | 803 | if (IS_ERR(rq)) |
| 808 | return PTR_ERR(rq); | 804 | return PTR_ERR(rq); |
| @@ -834,6 +830,8 @@ void nvme_start_keep_alive(struct nvme_ctrl *ctrl) | |||
| 834 | return; | 830 | return; |
| 835 | 831 | ||
| 836 | INIT_DELAYED_WORK(&ctrl->ka_work, nvme_keep_alive_work); | 832 | INIT_DELAYED_WORK(&ctrl->ka_work, nvme_keep_alive_work); |
| 833 | memset(&ctrl->ka_cmd, 0, sizeof(ctrl->ka_cmd)); | ||
| 834 | ctrl->ka_cmd.common.opcode = nvme_admin_keep_alive; | ||
| 837 | schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); | 835 | schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); |
| 838 | } | 836 | } |
| 839 | EXPORT_SYMBOL_GPL(nvme_start_keep_alive); | 837 | EXPORT_SYMBOL_GPL(nvme_start_keep_alive); |
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 27e31c00b306..0521e4707d1c 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h | |||
| @@ -183,6 +183,7 @@ struct nvme_ctrl { | |||
| 183 | struct work_struct scan_work; | 183 | struct work_struct scan_work; |
| 184 | struct work_struct async_event_work; | 184 | struct work_struct async_event_work; |
| 185 | struct delayed_work ka_work; | 185 | struct delayed_work ka_work; |
| 186 | struct nvme_command ka_cmd; | ||
| 186 | struct work_struct fw_act_work; | 187 | struct work_struct fw_act_work; |
| 187 | 188 | ||
| 188 | /* Power saving configuration */ | 189 | /* Power saving configuration */ |
