Messages in this thread Patch in this message |  | | From | Chao Shi <> | | Subject | [PATCH] nvme: reserve a keep-alive admin tag for all transports | | Date | Mon, 27 Apr 2026 22:29:11 -0400 |
| |
nvme_keep_alive_work() always allocates with BLK_MQ_REQ_RESERVED, but nvme_alloc_admin_tag_set() only sets reserved_tags for fabrics. Since commit b58da2d270db ("nvme: update keep alive interval when kato is modified"), userspace can start keep-alive on any transport via Set Features (KATO), after which the allocation trips WARN_ON_ONCE() in blk_mq_get_tag() and fails with -EWOULDBLOCK:
nvme nvme0: keep-alive failed: -11
Reserve one admin tag for keep-alive on all transports. Fabrics keeps two, the second being for the connect command.
Fixes: b58da2d270db ("nvme: update keep alive interval when kato is modified")
Found by FuzzNvme(Syzkaller with FEMU fuzzing framework).
Acked-by: Sungwoo Kim <iam@sung-woo.kim> Acked-by: Dave Tian <daveti@purdue.edu> Acked-by: Weidong Zhu <weizhu@fiu.edu> Signed-off-by: Chao Shi <coshi036@gmail.com> ---
Reproducer (run as root on an unpatched kernel with a PCIe NVMe device):
#include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/ioctl.h> #include <linux/nvme_ioctl.h>
int main(void) { struct nvme_admin_cmd cmd = {0}; int fd = open("/dev/nvme0", O_RDWR); if (fd < 0) { perror("open"); return 1; } cmd.opcode = 0x09; /* SET_FEATURES */ cmd.cdw10 = 0x0f; /* Feature ID: KATO */ cmd.cdw11 = 5; /* KATO = 5 seconds */ if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd) < 0) { perror("ioctl"); return 1; } return 0; }
Within ~kato/2 seconds after the program exits, dmesg shows:
nvme nvme0: keep alive interval updated from 0 ms to 5000 ms WARNING: CPU: 0 PID: ... at block/blk-mq-tag.c:148 blk_mq_get_tag+... nvme nvme0: keep-alive failed: -11
drivers/nvme/host/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 7bf228df6001..6db02ecde6d1 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -4850,8 +4850,13 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set, memset(set, 0, sizeof(*set)); set->ops = ops; set->queue_depth = NVME_AQ_MQ_TAG_DEPTH; + /* + * Reserve one tag for keep-alive, which is allocated with + * BLK_MQ_REQ_RESERVED and can be enabled on any transport via the + * KATO feature. Fabrics needs a second reserved tag for connect. + */ + set->reserved_tags = 1; if (ctrl->ops->flags & NVME_F_FABRICS) - /* Reserved for fabric connect and keep alive */ set->reserved_tags = 2; set->numa_node = ctrl->numa_node; if (ctrl->ops->flags & NVME_F_BLOCKING) -- 2.43.0
|  |