AEN and userspace updates
Subsystems (3)
v2 cover AEN and userspace updates
This series cleans up some duplicate AEN code, and ultimately adds change uevents for nvme devices that raise an AEN that the driver did not handle.
I have updated nvme-cli to have a more convenient way to retreive a log based on the AEN result, and intend to provide a udev rule to wrap that command when this goes through.
v1 -> v2;
Merge with nvme-4.15.
Squashed the AEN define centralization patches.
Using kasprintf for the uevent.
Removed async event helper function and made it inline.
Filter AEN notification only for events the kernel does not handle. This would be useful to prevent userspace from reacting events and reading logs that may alter what the kernel sees.
Keith Busch (5):
nvme: Centralize AEN defines
nvme/fc: remove unused "queue_size" field
nvme: Single AEN request
nvme: Unexport starting async event work
nvme: Send uevent for unhandled AEN completions
drivers/nvme/host/core.c | 57 ++++++++++++++++++++-------------------------- drivers/nvme/host/fc.c | 47 +++++++++++++------------------------- drivers/nvme/host/nvme.h | 6 ++--- drivers/nvme/host/pci.c | 14 ++++-------- drivers/nvme/host/rdma.c | 19 ++++------------ drivers/nvme/target/loop.c | 16 ++++--------- include/linux/nvme.h | 2 ++ 7 files changed, 57 insertions(+), 104 deletions(-)
Signature · 1 line
2.13.6
PATCH v2 1/5 nvme: Centralize AEN defines
All the transports were unnecessarilly duplicating the AEN request accounting. This defines everything in one place.
--- drivers/nvme/host/core.c | 2 +- drivers/nvme/host/fc.c | 33 ++++++++++++--------------------- drivers/nvme/host/nvme.h | 1 - drivers/nvme/host/pci.c | 12 +++--------- drivers/nvme/host/rdma.c | 14 +++----------- drivers/nvme/target/loop.c | 14 +++----------- include/linux/nvme.h | 2 ++ 7 files changed, 24 insertions(+), 54 deletions(-)
drivers/nvme/host/core.c +1 -1
@@ -2693,7 +2693,7 @@ EXPORT_SYMBOL_GPL(nvme_complete_async_event);void nvme_queue_async_events (struct nvme_ctrl *ctrl) { - ctrl->event_limit =NVME_NR_AERS ; + ctrl->event_limit =NVME_AEN_COMMANDS ;queue_work (nvme_wq, &ctrl->async_event_work); }EXPORT_SYMBOL_GPL (nvme_queue_async_events);
drivers/nvme/host/fc.c +12 -21
@@ -30,15 +30,6 @@/* *************************** Data Structures/Defines ****************** */ -/* -* We handle AEN commands ourselves and don't even let the -* block layer know about them. -*/ -#define NVME_FC_NR_AEN_COMMANDS 1 -#define NVME_FC_AQ_BLKMQ_DEPTH \ - (NVME_AQ_DEPTH - NVME_FC_NR_AEN_COMMANDS) -#define AEN_CMDID_BASE (NVME_FC_AQ_BLKMQ_DEPTH + 1) -enum nvme_fc_queue_flags {NVME_FC_Q_CONNECTED = (1 <<0 ), };
@@ -165,7 +156,7 @@ struct nvme_fc_ctrl {u32 iocnt;wait_queue_head_t ioabort_wait; -struct nvme_fc_fcp_op aen_ops[NVME_FC_NR_AEN_COMMANDS ]; +struct nvme_fc_fcp_op aen_ops[NVME_AEN_COMMANDS ];struct nvme_ctrl ctrl; };
@@ -1322,7 +1313,7 @@ nvme_fc_abort_aen_ops(struct nvme_fc_ctrl *ctrl)unsigned long flags;int i, ret; -for (i =0 ; i <NVME_FC_NR_AEN_COMMANDS ; i++, aen_op++) { +for (i =0 ; i <NVME_AEN_COMMANDS ; i++, aen_op++) {if (atomic_read (&aen_op->state) !=FCPOP_STATE_ACTIVE )continue ;
@@ -1592,7 +1583,7 @@ nvme_fc_init_aen_ops(struct nvme_fc_ctrl *ctrl)int i, ret; aen_op = ctrl->aen_ops; -for (i =0 ; i <NVME_FC_NR_AEN_COMMANDS ; i++, aen_op++) { +for (i =0 ; i <NVME_AEN_COMMANDS ; i++, aen_op++) { private =kzalloc (ctrl->lport->ops->fcprqst_priv_sz,GFP_KERNEL );if (!private)
@@ -1602,7 +1593,7 @@ nvme_fc_init_aen_ops(struct nvme_fc_ctrl *ctrl) sqe = &cmdiu->sqe; ret =__nvme_fc_init_request (ctrl, &ctrl->queues[0 ], aen_op, (struct request *)NULL , - (AEN_CMDID_BASE + i)); + (NVME_AQ_BLK_MQ_DEPTH + i));if (ret) {kfree (private);return ret;
@@ -1615,7 +1606,7 @@ nvme_fc_init_aen_ops(struct nvme_fc_ctrl *ctrl)memset (sqe,0 ,sizeof (*sqe)); sqe->common.opcode = nvme_admin_async_event;/* Note: core layer may overwrite the sqe.command_id value */ - sqe->common.command_id =AEN_CMDID_BASE + i; + sqe->common.command_id =NVME_AQ_BLK_MQ_DEPTH + i; }return 0 ; }
@@ -1627,7 +1618,7 @@ nvme_fc_term_aen_ops(struct nvme_fc_ctrl *ctrl)int i; aen_op = ctrl->aen_ops; -for (i =0 ; i <NVME_FC_NR_AEN_COMMANDS ; i++, aen_op++) { +for (i =0 ; i <NVME_AEN_COMMANDS ; i++, aen_op++) {if (!aen_op->fcp_req.private)continue ;
@@ -2185,7 +2176,7 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg, int aer_idx)bool terminating = false;blk_status_t ret; -if (aer_idx >NVME_FC_NR_AEN_COMMANDS ) +if (aer_idx >NVME_AEN_COMMANDS )return ;spin_lock_irqsave (&ctrl->lock, flags);
@@ -2445,16 +2436,16 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)* Create the admin queue */ -nvme_fc_init_queue (ctrl,0 ,NVME_FC_AQ_BLKMQ_DEPTH ); +nvme_fc_init_queue (ctrl,0 ,NVME_AQ_BLK_MQ_DEPTH ); ret =__nvme_fc_create_hw_queue (ctrl, &ctrl->queues[0 ],0 , -NVME_FC_AQ_BLKMQ_DEPTH ); +NVME_AQ_BLK_MQ_DEPTH );if (ret) goto out_free_queue; ret =nvme_fc_connect_admin_queue (ctrl, &ctrl->queues[0 ], -NVME_FC_AQ_BLKMQ_DEPTH , - (NVME_FC_AQ_BLKMQ_DEPTH /4 )); +NVME_AQ_BLK_MQ_DEPTH , + (NVME_AQ_BLK_MQ_DEPTH /4 ));if (ret) goto out_delete_hw_queue;
@@ -2854,7 +2845,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,memset (&ctrl->admin_tag_set,0 ,sizeof (ctrl->admin_tag_set)); ctrl->admin_tag_set.ops = &nvme_fc_admin_mq_ops; - ctrl->admin_tag_set.queue_depth =NVME_FC_AQ_BLKMQ_DEPTH ; + ctrl->admin_tag_set.queue_depth =NVME_AQ_BLK_MQ_DEPTH -1 ; ctrl->admin_tag_set.reserved_tags =2 ;/* fabric connect + Keep-Alive */ ctrl->admin_tag_set.numa_node =NUMA_NO_NODE ; ctrl->admin_tag_set.cmd_size = sizeof(struct nvme_fc_fcp_op) +
drivers/nvme/host/nvme.h +0 -1
@@ -300,7 +300,6 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl);int nvme_sec_submit (void *data,u16 spsp,u8 secp,void *buffer,size_t len,bool send); -#define NVME_NR_AERS 1void nvme_complete_async_event (struct nvme_ctrl *ctrl,__le16 status,union nvme_result *res);void nvme_queue_async_events (struct nvme_ctrl *ctrl);
drivers/nvme/host/pci.c +3 -9
@@ -35,12 +35,6 @@#define SQ_SIZE (depth) (depth * sizeof(struct nvme_command))#define CQ_SIZE (depth) (depth * sizeof(struct nvme_completion)) -/* -* We handle AEN commands ourselves and don't even let the -* block layer know about them. -*/ -#define NVME_AQ_BLKMQ_DEPTH (NVME_AQ_DEPTH - NVME_NR_AERS) -#define SGES_PER_PAGE (PAGE_SIZE / sizeof(struct nvme_sgl_desc))static int use_threaded_interrupts;
@@ -956,7 +950,7 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq,* for them but rather special case them here. */ if (unlikely (nvmeq->qid ==0 && - cqe->command_id >=NVME_AQ_BLKMQ_DEPTH )) { + cqe->command_id >=NVME_AQ_BLK_MQ_DEPTH )) {nvme_complete_async_event (&nvmeq->dev->ctrl, cqe->status, &cqe->result);return ;
@@ -1057,7 +1051,7 @@ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl, int aer_idx)memset (&c,0 ,sizeof (c)); c.common.opcode = nvme_admin_async_event; - c.common.command_id =NVME_AQ_BLKMQ_DEPTH + aer_idx; + c.common.command_id =NVME_AQ_BLK_MQ_DEPTH + aer_idx;spin_lock_irq (&nvmeq->q_lock);__nvme_submit_cmd (nvmeq, &c);
@@ -1528,7 +1522,7 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)* Subtract one to leave an empty queue entry for 'Full Queue' * condition. See NVM-Express 1.2 specification, section 4.1.2. */ - dev->admin_tagset.queue_depth =NVME_AQ_BLKMQ_DEPTH -1 ; + dev->admin_tagset.queue_depth =NVME_AQ_BLK_MQ_DEPTH -1 ; dev->admin_tagset.timeout =ADMIN_TIMEOUT ; dev->admin_tagset.numa_node =dev_to_node (dev->dev); dev->admin_tagset.cmd_size =nvme_pci_cmd_size (dev, false);
drivers/nvme/host/rdma.c +3 -11
@@ -41,14 +41,6 @@#define NVME_RDMA_MAX_INLINE_SEGMENTS 1 -/* -* We handle AEN commands ourselves and don't even let the -* block layer know about them. -*/ -#define NVME_RDMA_NR_AEN_COMMANDS 1 -#define NVME_RDMA_AQ_BLKMQ_DEPTH \ - (NVME_AQ_DEPTH - NVME_RDMA_NR_AEN_COMMANDS) -struct nvme_rdma_device {struct ib_device *dev;struct ib_pd *pd;
@@ -691,7 +683,7 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl, set = &ctrl->admin_tag_set;memset (set,0 ,sizeof (*set)); set->ops = &nvme_rdma_admin_mq_ops; - set->queue_depth =NVME_RDMA_AQ_BLKMQ_DEPTH ; + set->queue_depth =NVME_AQ_BLK_MQ_DEPTH -1 ; set->reserved_tags =2 ;/* connect + keep-alive */ set->numa_node =NUMA_NO_NODE ; set->cmd_size = sizeof(struct nvme_rdma_request) +
@@ -1319,7 +1311,7 @@ static void nvme_rdma_submit_async_event(struct nvme_ctrl *arg, int aer_idx)memset (cmd,0 ,sizeof (*cmd)); cmd->common.opcode = nvme_admin_async_event; - cmd->common.command_id =NVME_RDMA_AQ_BLKMQ_DEPTH ; + cmd->common.command_id =NVME_AQ_BLK_MQ_DEPTH ; cmd->common.flags |=NVME_CMD_SGL_METABUF ;nvme_rdma_set_sg_null (cmd);
@@ -1381,7 +1373,7 @@ static int __nvme_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc, int tag)* for them but rather special case them here. */ if (unlikely (nvme_rdma_queue_idx (queue) ==0 && - cqe->command_id >=NVME_RDMA_AQ_BLKMQ_DEPTH )) + cqe->command_id >=NVME_AQ_BLK_MQ_DEPTH ))nvme_complete_async_event (&queue->ctrl->ctrl, cqe->status, &cqe->result);else
drivers/nvme/target/loop.c +3 -11
@@ -23,14 +23,6 @@#define NVME_LOOP_MAX_SEGMENTS 256 -/* -* We handle AEN commands ourselves and don't even let the -* block layer know about them. -*/ -#define NVME_LOOP_NR_AEN_COMMANDS 1 -#define NVME_LOOP_AQ_BLKMQ_DEPTH \ - (NVME_AQ_DEPTH - NVME_LOOP_NR_AEN_COMMANDS) -struct nvme_loop_iod {struct nvme_request nvme_req;struct nvme_command cmd;
@@ -113,7 +105,7 @@ static void nvme_loop_queue_response(struct nvmet_req *req)* for them but rather special case them here. */ if (unlikely (nvme_loop_queue_idx (queue) ==0 && - cqe->command_id >=NVME_LOOP_AQ_BLKMQ_DEPTH )) { + cqe->command_id >=NVME_AQ_BLK_MQ_DEPTH )) {nvme_complete_async_event (&queue->ctrl->ctrl, cqe->status, &cqe->result); }else {
@@ -201,7 +193,7 @@ static void nvme_loop_submit_async_event(struct nvme_ctrl *arg, int aer_idx)memset (&iod->cmd,0 ,sizeof (iod->cmd)); iod->cmd.common.opcode = nvme_admin_async_event; - iod->cmd.common.command_id =NVME_LOOP_AQ_BLKMQ_DEPTH ; + iod->cmd.common.command_id =NVME_AQ_BLK_MQ_DEPTH ; iod->cmd.common.flags |=NVME_CMD_SGL_METABUF ; if (!nvmet_req_init(&iod->req, &queue->nvme_cq, &queue->nvme_sq,
@@ -357,7 +349,7 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)memset (&ctrl->admin_tag_set,0 ,sizeof (ctrl->admin_tag_set)); ctrl->admin_tag_set.ops = &nvme_loop_admin_mq_ops; - ctrl->admin_tag_set.queue_depth =NVME_LOOP_AQ_BLKMQ_DEPTH ; + ctrl->admin_tag_set.queue_depth =NVME_AQ_BLK_MQ_DEPTH -1 ; ctrl->admin_tag_set.reserved_tags =2 ;/* connect + keep-alive */ ctrl->admin_tag_set.numa_node =NUMA_NO_NODE ; ctrl->admin_tag_set.cmd_size = sizeof(struct nvme_loop_iod) +
include/linux/nvme.h +2 -0
@@ -90,6 +90,8 @@ enum { };#define NVME_AQ_DEPTH 32 +#define NVME_AEN_COMMANDS 1 +#define NVME_AQ_BLK_MQ_DEPTH (NVME_AQ_DEPTH - NVME_AEN_COMMANDS)enum {NVME_REG_CAP =0x0000 ,/* Controller Capabilities */
Signature · 1 line
2.13.6
Christoph Hellwig
maintainerPATCH v2 1/5 nvme: Centralize AEN defines
drivers/nvme/host/core.c EXPORT_SYMBOL_GPL(nvme_complete_async_event); · line 2696
Quoted 1 line
drivers/nvme/host/core.c +1
-0+ ctrl->event_limit =NVME_AEN_COMMANDS ;
Can we keep the NR_? E.g. NVME_NR_AEN_COMMANDS?
drivers/nvme/host/fc.c nvme_fc_abort_aen_ops(struct nvme_fc_ctrl *ctrl) · line 1318
Quoted 12 lines
drivers/nvme/host/fc.c +2
-1+struct nvme_fc_fcp_op aen_ops[NVME_AEN_COMMANDS ];struct nvme_ctrl ctrl; };@@ -1322,7 +1313,7 @@ nvme_fc_abort_aen_ops(struct nvme_fc_ctrl *ctrl)unsigned long flags;int i, ret; -for (i =0 ; i <NVME_FC_NR_AEN_COMMANDS ; i++, aen_op++) { +for (i =0 ; i <NVME_AEN_COMMANDS ; i++, aen_op++) {if (atomic_read (&aen_op->state) !=FCPOP_STATE_ACTIVE )continue ;
Kill the array and loop?
drivers/nvme/host/fc.c nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, · line 2848
Quoted 2 lines
drivers/nvme/host/fc.c +1
-1- ctrl->admin_tag_set.queue_depth =NVME_FC_AQ_BLKMQ_DEPTH ; + ctrl->admin_tag_set.queue_depth =NVME_AQ_BLK_MQ_DEPTH -1 ;
Shouldn't the -1 be factored into NVME_AQ_BLK_MQ_DEPTH? Either way I think we need some constant for it, and move the explanation for it from the PCI driver to the core somehow.
PATCH v2 2/5 nvme/fc: remove unused "queue_size" field
In reply to Keith BuschThis was being saved in a structure, but never used anywhere. The queue size is obtained through other means, so there's no reason to duplicate this without a user for it.
--- drivers/nvme/host/fc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/nvme/host/fc.c +3 -6
@@ -41,7 +41,6 @@ struct nvme_fc_queue {struct device *dev;struct blk_mq_hw_ctx *hctx;void *lldd_handle; -int queue_size;size_t cmnd_capsule_len;u32 qnum;u32 rqcnt;
@@ -1662,7 +1661,7 @@ nvme_fc_init_admin_hctx(struct blk_mq_hw_ctx *hctx, void *data, }static void -nvme_fc_init_queue (struct nvme_fc_ctrl *ctrl,int idx,size_t queue_size) +nvme_fc_init_queue (struct nvme_fc_ctrl *ctrl,int idx) {struct nvme_fc_queue *queue;
@@ -1678,8 +1677,6 @@ nvme_fc_init_queue(struct nvme_fc_ctrl *ctrl, int idx, size_t queue_size)else queue->cmnd_capsule_len =sizeof (struct nvme_command ); - queue->queue_size = queue_size; -/* * Considered whether we should allocate buffers for all SQEs * and CQEs and dma map them - mapping their respective entries
@@ -1803,7 +1800,7 @@ nvme_fc_init_io_queues(struct nvme_fc_ctrl *ctrl)int i;for (i =1 ; i < ctrl->ctrl.queue_count; i++) -nvme_fc_init_queue (ctrl, i, ctrl->ctrl.sqsize); +nvme_fc_init_queue (ctrl, i); } static void
@@ -2436,7 +2433,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)* Create the admin queue */ -nvme_fc_init_queue (ctrl,0 ,NVME_AQ_BLK_MQ_DEPTH ); +nvme_fc_init_queue (ctrl,0 ); ret =__nvme_fc_create_hw_queue (ctrl, &ctrl->queues[0 ],0 ,NVME_AQ_BLK_MQ_DEPTH );
Signature · 1 line
2.13.6
PATCH v2 2/5 nvme/fc: remove unused "queue_size" field
Quoted 9 lines · Keith Busch
This was being saved in a structure, but never used anywhere. The queue size is obtained through other means, so there's no reason to duplicate this without a user for it.
Reviewed-by Sagi Grimberg <sagi at grimberg.me>Signed-off-by Keith Busch <keith.busch at intel.com>--- drivers/nvme/host/fc.c | 9 +++------
Looks good. This stuff was left over when queuesize moved into the nvme ctrl.
-- james
PATCH v2 3/5 nvme: Single AEN request
In reply to Keith BuschThe driver can handle tracking only one AEN request, so this patch removes handling for multiple ones.
--- drivers/nvme/host/core.c | 28 +++------------------------- drivers/nvme/host/fc.c | 9 +++------ drivers/nvme/host/nvme.h | 3 +-- drivers/nvme/host/pci.c | 4 ++-- drivers/nvme/host/rdma.c | 5 +---- drivers/nvme/target/loop.c | 2 +- 6 files changed, 11 insertions(+), 40 deletions(-)
drivers/nvme/host/core.c +3 -25
@@ -2579,15 +2579,7 @@ static void nvme_async_event_work(struct work_struct *work)struct nvme_ctrl *ctrl = container_of(work, struct nvme_ctrl, async_event_work); -spin_lock_irq (&ctrl->lock); -while (ctrl->state ==NVME_CTRL_LIVE && ctrl->event_limit >0 ) { -int aer_idx = --ctrl->event_limit; - -spin_unlock_irq (&ctrl->lock); - ctrl->ops->submit_async_event (ctrl, aer_idx); -spin_lock_irq (&ctrl->lock); - } -spin_unlock_irq (&ctrl->lock); + ctrl->ops->submit_async_event (ctrl); }static bool nvme_ctrl_pp_status (struct nvme_ctrl *ctrl)
@@ -2659,22 +2651,8 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, union nvme_result *res) {u32 result =le32_to_cpu (res->u32); -bool done = true; -switch (le16_to_cpu (status) >>1 ) { -case NVME_SC_SUCCESS : - done = false; -/*FALLTHRU*/ -case NVME_SC_ABORT_REQ : - ++ctrl->event_limit; -if (ctrl->state ==NVME_CTRL_LIVE ) -queue_work (nvme_wq, &ctrl->async_event_work); -break ; -default : -break ; - } - -if (done) +if (le16_to_cpu (status) >>1 !=NVME_SC_SUCCESS )return ;switch (result &0xff07 ) {
@@ -2688,12 +2666,12 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,default :dev_warn (ctrl->device,"async event result %08x\n" , result); } +queue_work (nvme_wq, &ctrl->async_event_work); }EXPORT_SYMBOL_GPL (nvme_complete_async_event);void nvme_queue_async_events (struct nvme_ctrl *ctrl) { - ctrl->event_limit =NVME_AEN_COMMANDS ;queue_work (nvme_wq, &ctrl->async_event_work); }EXPORT_SYMBOL_GPL (nvme_queue_async_events);
drivers/nvme/host/fc.c +3 -6
@@ -2165,7 +2165,7 @@ nvme_fc_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag) }static void -nvme_fc_submit_async_event (struct nvme_ctrl *arg,int aer_idx) +nvme_fc_submit_async_event (struct nvme_ctrl *arg) {struct nvme_fc_ctrl *ctrl =to_fc_ctrl (arg);struct nvme_fc_fcp_op *aen_op;
@@ -2173,9 +2173,6 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg, int aer_idx)bool terminating = false;blk_status_t ret; -if (aer_idx >NVME_AEN_COMMANDS ) -return ; -spin_lock_irqsave (&ctrl->lock, flags);if (ctrl->flags &FCCTRL_TERMIO ) terminating = true;
@@ -2184,13 +2181,13 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg, int aer_idx)if (terminating)return ; - aen_op = &ctrl->aen_ops[aer_idx]; + aen_op = &ctrl->aen_ops[0 ]; ret =nvme_fc_start_fcp_op (ctrl, aen_op->queue, aen_op,0 ,NVMEFC_FCP_NODATA );if (ret)dev_err (ctrl->ctrl.device, -"failed async event work [%d]\n" , aer_idx); +"failed async event work\n" ); } static void
drivers/nvme/host/nvme.h +1 -2
@@ -160,7 +160,6 @@ struct nvme_ctrl {u16 nssa;u16 nr_streams;atomic_t abort_limit; -u8 event_limit;u8 vwc;u32 vs;u32 sgls;
@@ -234,7 +233,7 @@ struct nvme_ctrl_ops {int (*reg_write32)(struct nvme_ctrl *ctrl,u32 off,u32 val);int (*reg_read64)(struct nvme_ctrl *ctrl,u32 off,u64 *val);void (*free_ctrl)(struct nvme_ctrl *ctrl); -void (*submit_async_event)(struct nvme_ctrl *ctrl,int aer_idx); +void (*submit_async_event)(struct nvme_ctrl *ctrl);int (*delete_ctrl)(struct nvme_ctrl *ctrl);int (*get_address)(struct nvme_ctrl *ctrl,char *buf,int size);int (*reinit_request)(void *data,struct request *rq);
drivers/nvme/host/pci.c +2 -2
@@ -1043,7 +1043,7 @@ static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)return __nvme_poll (nvmeq, tag); } -static void nvme_pci_submit_async_event (struct nvme_ctrl *ctrl,int aer_idx) +static void nvme_pci_submit_async_event (struct nvme_ctrl *ctrl) {struct nvme_dev *dev =to_nvme_dev (ctrl);struct nvme_queue *nvmeq = dev->queues[0 ];
@@ -1051,7 +1051,7 @@ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl, int aer_idx)memset (&c,0 ,sizeof (c)); c.common.opcode = nvme_admin_async_event; - c.common.command_id =NVME_AQ_BLK_MQ_DEPTH + aer_idx; + c.common.command_id =NVME_AQ_BLK_MQ_DEPTH ;spin_lock_irq (&nvmeq->q_lock);__nvme_submit_cmd (nvmeq, &c);
drivers/nvme/host/rdma.c +1 -4
@@ -1294,7 +1294,7 @@ static struct blk_mq_tags *nvme_rdma_tagset(struct nvme_rdma_queue *queue)return queue->ctrl->tag_set.tags[queue_idx -1 ]; } -static void nvme_rdma_submit_async_event (struct nvme_ctrl *arg,int aer_idx) +static void nvme_rdma_submit_async_event (struct nvme_ctrl *arg) {struct nvme_rdma_ctrl *ctrl =to_rdma_ctrl (arg);struct nvme_rdma_queue *queue = &ctrl->queues[0 ];
@@ -1304,9 +1304,6 @@ static void nvme_rdma_submit_async_event(struct nvme_ctrl *arg, int aer_idx)struct ib_sge sge;int ret; -if (WARN_ON_ONCE (aer_idx !=0 )) -return ; -ib_dma_sync_single_for_cpu (dev, sqe->dma,sizeof (*cmd),DMA_TO_DEVICE );memset (cmd,0 ,sizeof (*cmd));
drivers/nvme/target/loop.c +1 -1
@@ -185,7 +185,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,return BLK_STS_OK ; } -static void nvme_loop_submit_async_event (struct nvme_ctrl *arg,int aer_idx) +static void nvme_loop_submit_async_event (struct nvme_ctrl *arg) {struct nvme_loop_ctrl *ctrl =to_loop_ctrl (arg);struct nvme_loop_queue *queue = &ctrl->queues[0 ];
Signature · 1 line
2.13.6
Christoph Hellwig
maintainerPATCH v2 3/5 nvme: Single AEN request
Looks fine,
PATCH v2 4/5 nvme: Unexport starting async event work
In reply to Keith BuschAsync event work is for core use only and should not be called directly from drivers.
--- drivers/nvme/host/core.c | 8 +------- drivers/nvme/host/nvme.h | 1 - 2 files changed, 1 insertion(+), 8 deletions(-)
drivers/nvme/host/core.c +1 -7
@@ -2670,12 +2670,6 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, }EXPORT_SYMBOL_GPL (nvme_complete_async_event); -void nvme_queue_async_events (struct nvme_ctrl *ctrl) -{ -queue_work (nvme_wq, &ctrl->async_event_work); -} -EXPORT_SYMBOL_GPL (nvme_queue_async_events); -void nvme_stop_ctrl (struct nvme_ctrl *ctrl) {nvme_stop_keep_alive (ctrl);
@@ -2692,7 +2686,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl)if (ctrl->queue_count >1 ) {nvme_queue_scan (ctrl); -nvme_queue_async_events (ctrl); +queue_work (nvme_wq, &ctrl->async_event_work);nvme_start_queues (ctrl); } }
drivers/nvme/host/nvme.h +0 -1
@@ -301,7 +301,6 @@ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,void nvme_complete_async_event (struct nvme_ctrl *ctrl,__le16 status,union nvme_result *res); -void nvme_queue_async_events (struct nvme_ctrl *ctrl);void nvme_stop_queues (struct nvme_ctrl *ctrl);void nvme_start_queues (struct nvme_ctrl *ctrl);
Signature · 1 line
2.13.6
Christoph Hellwig
maintainerPATCH v2 4/5 nvme: Unexport starting async event work
Looks good,
PATCH v2 5/5 nvme: Send uevent for unhandled AEN completions
In reply to Keith BuschThis will give udev a chance to handle asynchronous event notification and clear the log to unmask future events of the same type. Since the core driver allows only one AEN request at a time, we can only have one possible oustanding uevent to send. This implementation saves the last AEN result from the IRQ handler, and sends the uevent change notification when the AEN work is rescheduled.
AEN events that the kernel handles directly will not create a uevent. Such events will stop being sent to the user as new handlers are added to the kernel.
--- drivers/nvme/host/core.c | 21 +++++++++++++++++++++ drivers/nvme/host/nvme.h | 1 + 2 files changed, 22 insertions(+)
drivers/nvme/host/core.c +21 -0
@@ -2574,11 +2574,27 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl) }EXPORT_SYMBOL_GPL (nvme_remove_namespaces); +static void nvme_aen_uevent (struct nvme_ctrl *ctrl) +{ +char *envp[2 ] = {NULL ,NULL }; +u32 aen = ctrl->aen; + + ctrl->aen =0 ; +if (!aen) +return ; + +if (!envp[0 ]) +return ; +kobject_uevent_env (&ctrl->device->kobj,KOBJ_CHANGE , envp); +kfree (envp[0 ]); +} +static void nvme_async_event_work (struct work_struct *work) {struct nvme_ctrl *ctrl = container_of(work, struct nvme_ctrl, async_event_work); +nvme_aen_uevent (ctrl); ctrl->ops->submit_async_event (ctrl); }
@@ -2655,6 +2671,10 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,if (le16_to_cpu (status) >>1 !=NVME_SC_SUCCESS )return ; +/* +* Set result for udev only for AEN types that the kernel does not +* directly handle. +*/ switch (result &0xff07 ) {case NVME_AER_NOTICE_NS_CHANGED :dev_info (ctrl->device,"rescanning\n" );
@@ -2664,6 +2684,7 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,queue_work (nvme_wq, &ctrl->fw_act_work);break ;default : + ctrl->aen = result;dev_warn (ctrl->device,"async event result %08x\n" , result); }queue_work (nvme_wq, &ctrl->async_event_work);
drivers/nvme/host/nvme.h +1 -0
@@ -166,6 +166,7 @@ struct nvme_ctrl {u16 kas;u8 npss;u8 apsta; +u32 aen;unsigned int shutdown_timeout;unsigned int kato;bool subsystem;
Signature · 1 line
2.13.6
PATCH v2 5/5 nvme: Send uevent for unhandled AEN completions
Quoted 4 lines · Keith Busch
drivers/nvme/host/core.c +4
-0+static void nvme_aen_uevent (struct nvme_ctrl *ctrl) +{ +char *envp[2 ] = {NULL ,NULL }; +u32 aen = ctrl->aen;
drivers/nvme/host/core.c void nvme_remove_namespaces(struct nvme_ctrl *ctrl) · line 2590
Quoted 10 lines
drivers/nvme/host/core.c +10
-0+ + ctrl->aen =0 ; +if (!aen) +return ; + +if (!envp[0 ]) +return ; +kobject_uevent_env (&ctrl->device->kobj,KOBJ_CHANGE , envp); +kfree (envp[0 ]); +}
Uh, the string format dissappeared on me. Resending...