Asynchronous events for udev
Subsystems (3)
v3 cover Asynchronous events for udev
This series updates asynchronous event notification throughout the driver by centralizing common definitions, simplifying the code with a single outstanding asynchronous event request, and ending with creating a change uevent if the event result matches a whitelist of events to notify.
v2 -> v3:
Merged to current nvme-4.15
Use a whitelist instead of notifying all unhandled events
Added define for the blk-mq tagset queue_depth (patch 1/5)
Added reviews from previous round
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 some asynchronous events
drivers/nvme/host/core.c | 62 ++++++++++++++++++++++++---------------------- drivers/nvme/host/fc.c | 47 ++++++++++++----------------------- drivers/nvme/host/nvme.h | 6 ++--- drivers/nvme/host/pci.c | 18 +++----------- drivers/nvme/host/rdma.c | 19 +++----------- drivers/nvme/target/loop.c | 16 +++--------- include/linux/nvme.h | 12 +++++++++ 7 files changed, 75 insertions(+), 105 deletions(-)
Signature · 1 line
2.13.6
PATCH v3 1/5 nvme: Centralize AEN defines
All the transports were unnecessarilly duplicating the AEN request accounting. This patch 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 | 16 +++------------- drivers/nvme/host/rdma.c | 14 +++----------- drivers/nvme/target/loop.c | 14 +++----------- include/linux/nvme.h | 8 ++++++++ 7 files changed, 30 insertions(+), 58 deletions(-)
drivers/nvme/host/core.c +1 -1
@@ -2792,7 +2792,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_NR_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 ), };
@@ -167,7 +158,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_NR_AEN_COMMANDS ];struct nvme_ctrl ctrl; };
@@ -1533,7 +1524,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_NR_AEN_COMMANDS ; i++, aen_op++) {if (atomic_read (&aen_op->state) !=FCPOP_STATE_ACTIVE )continue ;
@@ -1803,7 +1794,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_NR_AEN_COMMANDS ; i++, aen_op++) { private =kzalloc (ctrl->lport->ops->fcprqst_priv_sz,GFP_KERNEL );if (!private)
@@ -1813,7 +1804,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;
@@ -1826,7 +1817,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 ; }
@@ -1838,7 +1829,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_NR_AEN_COMMANDS ; i++, aen_op++) {if (!aen_op->fcp_req.private)continue ;
@@ -2389,7 +2380,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_NR_AEN_COMMANDS )return ;spin_lock_irqsave (&ctrl->lock, flags);
@@ -2651,16 +2642,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;
@@ -3065,7 +3056,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_MQ_TAG_DEPTH ; 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
@@ -313,7 +313,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 -13
@@ -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);
@@ -1524,11 +1518,7 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev) dev->admin_tagset.ops = &nvme_mq_admin_ops; dev->admin_tagset.nr_hw_queues =1 ; -/* -* 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_MQ_TAG_DEPTH ; 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;
@@ -690,7 +682,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_MQ_TAG_DEPTH ; set->reserved_tags =2 ;/* connect + keep-alive */ set->numa_node =NUMA_NO_NODE ; set->cmd_size = sizeof(struct nvme_rdma_request) +
@@ -1318,7 +1310,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);
@@ -1380,7 +1372,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;
@@ -112,7 +104,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 {
@@ -200,7 +192,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,
@@ -356,7 +348,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_MQ_TAG_DEPTH ; 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 +8 -0
@@ -90,6 +90,14 @@ enum { };#define NVME_AQ_DEPTH 32 +#define NVME_NR_AEN_COMMANDS 1 +#define NVME_AQ_BLK_MQ_DEPTH (NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS) + +/* +* Subtract one to leave an empty queue entry for 'Full Queue' condition. See +* NVM-Express 1.2 specification, section 4.1.2. +*/ +#define NVME_AQ_MQ_TAG_DEPTH (NVME_AQ_BLK_MQ_DEPTH - 1)enum {NVME_REG_CAP =0x0000 ,/* Controller Capabilities */
Signature · 1 line
2.13.6
PATCH v3 1/5 nvme: Centralize AEN defines
Quoted 4 lines · Keith Busch
All the transports were unnecessarilly duplicating the AEN request accounting. This patch defines everything in one place.
Signed-off-by Keith Busch <keith.busch at intel.com>
Christoph Hellwig
maintainerPATCH v3 1/5 nvme: Centralize AEN defines
In reply to Keith BuschLooks fine:
Quoted 6 lines
include/linux/nvme.h +0
-0@@ -90,6 +90,14 @@ enum { };
include/linux/nvme.h enum { · line 100
Quoted 10 lines
include/linux/nvme.h +8
-0#define NVME_AQ_DEPTH 32 +#define NVME_NR_AEN_COMMANDS 1 +#define NVME_AQ_BLK_MQ_DEPTH (NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS) + +/* +* Subtract one to leave an empty queue entry for 'Full Queue' condition. See +* NVM-Express 1.2 specification, section 4.1.2. +*/ +#define NVME_AQ_MQ_TAG_DEPTH (NVME_AQ_BLK_MQ_DEPTH - 1)
But none of these (including NVME_AQ_DEPTH) really is a protocol constant, so this should probably move to drivers/nvme/host/nvme.h.
No need to do that in this patchseries, though.
PATCH v3 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
@@ -43,7 +43,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;
@@ -1873,7 +1872,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;
@@ -1889,8 +1888,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
@@ -2014,7 +2011,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
@@ -2642,7 +2639,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
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v3 2/5 nvme/fc: remove unused "queue_size" field
Quoted 9 lines · James Smart
On 11/7/2017 2:13 PM, Keith Busch wrote:
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 [1]<sagi at grimberg.me>
Signed-off-by: Keith Busch [2]<keith.busch at intel.com>
---
Quoted 7 lines
drivers/nvme/host/fc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)I had reviewed the v2.
Reviewed-by James Smart [3]<james.smart at broadcom.com>
Indeed, sorry about that, and thank you for the review.
PATCH v3 2/5 nvme/fc: remove unused "queue_size" field
In reply to Keith BuschQuoted 3 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.
Christoph Hellwig
maintainerPATCH v3 2/5 nvme/fc: remove unused "queue_size" field
In reply to Keith BuschLooks fine,
PATCH v3 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
@@ -2683,15 +2683,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)
@@ -2758,22 +2750,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 ) {
@@ -2787,12 +2765,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_NR_AEN_COMMANDS ;queue_work (nvme_wq, &ctrl->async_event_work); }EXPORT_SYMBOL_GPL (nvme_queue_async_events);
drivers/nvme/host/fc.c +3 -6
@@ -2369,7 +2369,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;
@@ -2377,9 +2377,6 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg, int aer_idx)bool terminating = false;blk_status_t ret; -if (aer_idx >NVME_NR_AEN_COMMANDS ) -return ; -spin_lock_irqsave (&ctrl->lock, flags);if (ctrl->flags &FCCTRL_TERMIO ) terminating = true;
@@ -2388,13 +2385,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
@@ -162,7 +162,6 @@ struct nvme_ctrl {u16 nssa;u16 nr_streams;atomic_t abort_limit; -u8 event_limit;u8 vwc;u32 vs;u32 sgls;
@@ -237,7 +236,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);void (*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
@@ -1293,7 +1293,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 ];
@@ -1303,9 +1303,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
@@ -184,7 +184,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
PATCH v3 3/5 nvme: Single AEN request
Quoted 13 lines · Keith Busch
static bool
nvme_ctrl_pp_status(struct nvme_ctrl *ctrl)drivers/nvme/host/core.c +0
-7@@ -2758,22 +2750,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;
drivers/nvme/host/core.c void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, · line 2755
Quoted 10 lines
drivers/nvme/host/core.c +1
-8-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 ;
If le16_to_cpu(status) >> 1 is NVME_SC_ABORT_REQ, the current async event request is aborted and there is no pending request in the queue of async event request of the target. Why do you choose not to submit another async event request to the target?
Christoph Hellwig
maintainerPATCH v3 3/5 nvme: Single AEN request
Quoted 3 lines · Guan Junxiong
If
le16_to_cpu(status)>> 1 isNVME_SC_ABORT_REQ, the current async event request is aborted and there is no pending request in the queue of async event request of the target. Why do you choose not to submit another async event request to the target?
We're never going to send an abort for the AER, so this status code will only happen if the controller is being torn down, in that case we don't want to submit another one until the controller is set up again.
PATCH v3 3/5 nvme: Single AEN request
Quoted 8 lines · Christoph Hellwig
Quoted 3 lines · Guan Junxiong
If
le16_to_cpu(status)>> 1 isNVME_SC_ABORT_REQ, the current async event request is aborted and there is no pending request in the queue of async event request of the target. Why do you choose not to submit another async event request to the target?We're never going to send an abort for the AER, so this status code will only happen if the controller is being torn down, in that case we don't want to submit another one until the controller is set up again.
Yeah, reclaiming the AER count on abort was a trick for controller resets when we were tracking those requests. Back then, every reset you'd see at least one "Cancelling I/O QID 0" message for AER commands. We've had a better way to handle this wor a while now, so that was left-over dead code.
Christoph Hellwig
maintainerPATCH v3 3/5 nvme: Single AEN request
In reply to Keith BuschLooks good,
PATCH v3 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
@@ -2769,12 +2769,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);
@@ -2791,7 +2785,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
@@ -314,7 +314,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
PATCH v3 4/5 nvme: Unexport starting async event work
Quoted 5 lines · Keith Busch
Async event work is for core use only and should not be called directly from drivers.
Reviewed-by Christoph Hellwig <hch at lst.de>Signed-off-by Keith Busch <keith.busch at intel.com>
PATCH v3 5/5 nvme: Send uevent for some asynchronous events
In reply to Keith BuschThis will give udev a chance to observe and handle asynchronous event notifications and clear the log to unmask future events of the same type. The driver will create a change uevent of the asyncronuos event result before submitting the next AEN request to the device if a completed AEN event is of type error, smart, command set or vendor specific,
--- drivers/nvme/host/core.c | 28 ++++++++++++++++++++++++++++ drivers/nvme/host/nvme.h | 1 + include/linux/nvme.h | 4 ++++ 3 files changed, 33 insertions(+)
drivers/nvme/host/core.c +28 -0
@@ -2678,11 +2678,28 @@ 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 ; + + envp[0 ] =kasprintf (GFP_KERNEL ,"NVME_AEN=%#08x" , aen); +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); }
@@ -2754,6 +2771,17 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,if (le16_to_cpu (status) >>1 !=NVME_SC_SUCCESS )return ; +switch (result &0x7 ) { +case NVME_AER_ERROR : +case NVME_AER_SMART : +case NVME_AER_CSS : +case NVME_AER_VS : + ctrl->aen = result; +break ; +default : +break ; + } +switch (result &0xff07 ) {case NVME_AER_NOTICE_NS_CHANGED :dev_info (ctrl->device,"rescanning\n" );
drivers/nvme/host/nvme.h +1 -0
@@ -168,6 +168,7 @@ struct nvme_ctrl {u16 kas;u8 npss;u8 apsta; +u32 aen;unsigned int shutdown_timeout;unsigned int kato;bool subsystem;
include/linux/nvme.h +4 -0
@@ -428,6 +428,10 @@ enum { };enum { +NVME_AER_ERROR =0 , +NVME_AER_SMART =1 , +NVME_AER_CSS =6 , +NVME_AER_VS =7 ,NVME_AER_NOTICE_NS_CHANGED =0x0002 ,NVME_AER_NOTICE_FW_ACT_STARTING =0x0102 , };
Signature · 1 line
2.13.6
PATCH v3 5/5 nvme: Send uevent for some asynchronous events
Quoted 7 lines · Keith Busch
This will give udev a chance to observe and handle asynchronous event notifications and clear the log to unmask future events of the same type. The driver will create a change uevent of the asyncronuos event result before submitting the next AEN request to the device if a completed AEN event is of type error, smart, command set or vendor specific,
Signed-off-by Keith Busch <keith.busch at intel.com>
Christoph Hellwig
maintainerPATCH v3 5/5 nvme: Send uevent for some asynchronous events
In reply to Keith BuschQuoted 18 lines · Keith Busch
This will give udev a chance to observe and handle asynchronous event notifications and clear the log to unmask future events of the same type. The driver will create a change uevent of the asyncronuos event result before submitting the next AEN request to the device if a completed AEN event is of type error, smart, command set or vendor specific,
Signed-off-by Keith Busch <keith.busch at intel.com>--- drivers/nvme/host/core.c | 28 ++++++++++++++++++++++++++++ drivers/nvme/host/nvme.h | 1 + include/linux/nvme.h | 4 ++++ 3 files changed, 33 insertions(+)drivers/nvme/host/core.c +0
-0
drivers/nvme/host/core.c void nvme_remove_namespaces(struct nvme_ctrl *ctrl) · line 2686
Quoted 9 lines
drivers/nvme/host/core.c +6
-0@@ -2678,11 +2678,28 @@ 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 ;
Seems like we should use cmpxchg on aen.
Quoted 20 lines
drivers/nvme/host/core.c +11
-0+if (!aen) +return ; + + envp[0 ] =kasprintf (GFP_KERNEL ,"NVME_AEN=%#08x" , aen); +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); }
drivers/nvme/host/core.c void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, · line 2779
Quoted 9 lines
drivers/nvme/host/core.c +6
-0@@ -2754,6 +2771,17 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,if (le16_to_cpu (status) >>1 !=NVME_SC_SUCCESS )return ; +switch (result &0x7 ) { +case NVME_AER_ERROR : +case NVME_AER_SMART : +case NVME_AER_CSS : +case NVME_AER_VS : + ctrl->aen = result;
Can we call the field aen_result?
Given that the rest of the series looks good I'd be tempted to just fix that up and apply it. Are you ok with that?
PATCH v3 5/5 nvme: Send uevent for some asynchronous events
Quoted 10 lines · Christoph Hellwig
drivers/nvme/host/core.c void nvme_remove_namespaces(struct nvme_ctrl *ctrl) · line 2686
Quoted 6 lines · Keith Busch
drivers/nvme/host/core.c +6
-0+static void nvme_aen_uevent (struct nvme_ctrl *ctrl) +{ +char *envp[2 ] = {NULL ,NULL }; +u32 aen = ctrl->aen; + + ctrl->aen =0 ;Seems like we should use cmpxchg on aen.
Quoted 6 lines
drivers/nvme/host/core.c void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, · line 2779
Quoted 1 line
drivers/nvme/host/core.c +1
-0+ ctrl->aen = result;Can we call the field
aen_result?Given that the rest of the series looks good I'd be tempted to just fix that up and apply it. Are you ok with that?
Thanks, the suggestions sound good to me. If you want to edit the commit when applying, I would much appreciate.
Christoph Hellwig
maintainerPATCH v3 5/5 nvme: Send uevent for some asynchronous events
Quoted 11 lines · Keith Busch
Quoted 8 lines
Seems like we should use cmpxchg on aen.
drivers/nvme/host/core.c void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, · line 2779
Quoted 1 line
drivers/nvme/host/core.c +1
-0+ ctrl->aen = result;Can we call the field
aen_result?Given that the rest of the series looks good I'd be tempted to just fix that up and apply it. Are you ok with that?
Thanks, the suggestions sound good to me. If you want to edit the commit when applying, I would much appreciate.
I'll just do the rename for now. I'll ponder the cmpxchg a little more, and if I think we need it I'll send a follow on patch.