Skip to content

Commit e7ad43c

Browse files
Keith BuschChristoph Hellwig
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]>
1 parent ec51f8e commit e7ad43c

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
@@ -1253,6 +1253,7 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
12531253
* effects say only one namespace is affected.
12541254
*/
12551255
if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
1256+
mutex_lock(&ctrl->scan_lock);
12561257
nvme_start_freeze(ctrl);
12571258
nvme_wait_freeze(ctrl);
12581259
}
@@ -1281,8 +1282,10 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
12811282
*/
12821283
if (effects & NVME_CMD_EFFECTS_LBCC)
12831284
nvme_update_formats(ctrl);
1284-
if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK))
1285+
if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
12851286
nvme_unfreeze(ctrl);
1287+
mutex_unlock(&ctrl->scan_lock);
1288+
}
12861289
if (effects & NVME_CMD_EFFECTS_CCC)
12871290
nvme_init_identify(ctrl);
12881291
if (effects & (NVME_CMD_EFFECTS_NIC | NVME_CMD_EFFECTS_NCC))
@@ -3401,6 +3404,7 @@ static void nvme_scan_work(struct work_struct *work)
34013404
if (nvme_identify_ctrl(ctrl, &id))
34023405
return;
34033406

3407+
mutex_lock(&ctrl->scan_lock);
34043408
nn = le32_to_cpu(id->nn);
34053409
if (ctrl->vs >= NVME_VS(1, 1, 0) &&
34063410
!(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
@@ -3409,6 +3413,7 @@ static void nvme_scan_work(struct work_struct *work)
34093413
}
34103414
nvme_scan_ns_sequential(ctrl, nn);
34113415
out_free_id:
3416+
mutex_unlock(&ctrl->scan_lock);
34123417
kfree(id);
34133418
down_write(&ctrl->namespaces_rwsem);
34143419
list_sort(NULL, &ctrl->namespaces, ns_cmp);
@@ -3652,6 +3657,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
36523657

36533658
ctrl->state = NVME_CTRL_NEW;
36543659
spin_lock_init(&ctrl->lock);
3660+
mutex_init(&ctrl->scan_lock);
36553661
INIT_LIST_HEAD(&ctrl->namespaces);
36563662
init_rwsem(&ctrl->namespaces_rwsem);
36573663
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)