Skip to content

Commit 9550edd

Browse files
Keith Buschjfvogel
authored andcommitted
nvme: lock NS list changes while handling command effects
If a controller supports the NS Change Notification, the namespace scan_work is automatically triggered after attaching a new namespace. Occasionally the namespace scan_work may append the new namespace to the list before the admin command effects handling is completed. The effects handling unfreezes namespaces, but if it unfreezes the newly attached namespace, its request_queue freeze depth will be off and we'll hit the warning in blk_mq_unfreeze_queue(). On the next namespace add, we will fail to freeze that queue due to the previous bad accounting and deadlock waiting for frozen. Fix that by preventing scan work from altering the namespace list while command effects handling needs to pair freeze with unfreeze. Reported-by: Wen Xiong <[email protected]> Tested-by: Wen Xiong <[email protected]> Signed-off-by: Keith Busch <[email protected]> Reviewed-by: Chaitanya Kulkarni <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> (cherry picked from commit e7ad43c) Orabug: 29933720 Signed-off-by: Alan Adamson <[email protected]> Reviewed-by: John Donnelly <[email protected]>
1 parent 8b226cf commit 9550edd

File tree

2 files changed

+8
-1
lines changed

2 files changed

+8
-1
lines changed

drivers/nvme/host/core.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,7 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
12181218
* effects say only one namespace is affected.
12191219
*/
12201220
if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
1221+
mutex_lock(&ctrl->scan_lock);
12211222
nvme_start_freeze(ctrl);
12221223
nvme_wait_freeze(ctrl);
12231224
}
@@ -1246,8 +1247,10 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
12461247
*/
12471248
if (effects & NVME_CMD_EFFECTS_LBCC)
12481249
nvme_update_formats(ctrl);
1249-
if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK))
1250+
if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
12501251
nvme_unfreeze(ctrl);
1252+
mutex_unlock(&ctrl->scan_lock);
1253+
}
12511254
if (effects & NVME_CMD_EFFECTS_CCC)
12521255
nvme_init_identify(ctrl);
12531256
if (effects & (NVME_CMD_EFFECTS_NIC | NVME_CMD_EFFECTS_NCC))
@@ -3370,6 +3373,7 @@ static void nvme_scan_work(struct work_struct *work)
33703373
if (nvme_identify_ctrl(ctrl, &id))
33713374
return;
33723375

3376+
mutex_lock(&ctrl->scan_lock);
33733377
nn = le32_to_cpu(id->nn);
33743378
if (ctrl->vs >= NVME_VS(1, 1, 0) &&
33753379
!(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
@@ -3378,6 +3382,7 @@ static void nvme_scan_work(struct work_struct *work)
33783382
}
33793383
nvme_scan_ns_sequential(ctrl, nn);
33803384
out_free_id:
3385+
mutex_unlock(&ctrl->scan_lock);
33813386
kfree(id);
33823387
down_write(&ctrl->namespaces_rwsem);
33833388
list_sort(NULL, &ctrl->namespaces, ns_cmp);
@@ -3621,6 +3626,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
36213626

36223627
ctrl->state = NVME_CTRL_NEW;
36233628
spin_lock_init(&ctrl->lock);
3629+
mutex_init(&ctrl->scan_lock);
36243630
INIT_LIST_HEAD(&ctrl->namespaces);
36253631
init_rwsem(&ctrl->namespaces_rwsem);
36263632
ctrl->dev = dev;

drivers/nvme/host/nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ struct nvme_ctrl {
154154
enum nvme_ctrl_state state;
155155
bool identified;
156156
spinlock_t lock;
157+
struct mutex scan_lock;
157158
const struct nvme_ctrl_ops *ops;
158159
struct request_queue *admin_q;
159160
struct request_queue *connect_q;

0 commit comments

Comments
 (0)