nvmet: Enable AENs support for Discovery controllers
Subsystems (2)
v2 cover nvmet: Enable AENs support for Discovery controllers
v2 - corrected two patch descriptions and a patch's author
Technical proposal 8002 defines enhancements to provide NVMe-oF with the same level of resource enumeration as is available with local PCIe-based NVMe devices. It defines an NVMe-oF level mechanism for notifying provisioned hosts about remote resource state changes (i.e., added, removed, modified), specifically Discovery Log changes.
These changes allow an optional explicit persistent connection to Discovery controllers, and defines a mechanism to indicate changes occurring on Subsystems and Namespace controllers via Asynchronous Event Notifications.
Jay Sternberg (10):
nvmet: Provide aen bit functions for multiple controller types
nvmet: Change aen mask functions to use bit numbers
nvmet: Allow Keep Alive for Discovery controller
nvmet: Make kato and AEN processing for use by other controllers
nvmet: Add defines for discovery change async events
nvmet: Add support to Discovery controllers for commands
nvmet: Add parent to nvmet_referral_disable
nvmet: Maintain a global list of ports
nvmet: Allow all hosts access to the Discovery subsystem
nvmet: Enable Discovery Controller AENs
Phil Cayton (1):
nvmet: Provide adding AENs for multiple controller types
drivers/nvme/target/admin-cmd.c | 63 +++++++++++---------- drivers/nvme/target/configfs.c | 26 ++++++++- drivers/nvme/target/core.c | 69 ++++++----------------- drivers/nvme/target/discovery.c | 121 +++++++++++++++++++++++++++++++++++++++- drivers/nvme/target/nvmet.h | 49 ++++++++++++++-- include/linux/nvme.h | 15 ++++- 6 files changed, 247 insertions(+), 96 deletions(-)
Signature · 1 line
1.8.3.1
PATCH v2 1/11 nvmet: Provide aen bit functions for multiple controller types
Move nvmet_aen_disabled and nvmet_clear_aen in preparation for other types of controllers to use, initially the discovery controller.
---
v2 - unchanged
drivers/nvme/target/admin-cmd.c | 13 ------------- drivers/nvme/target/core.c | 7 ------- drivers/nvme/target/nvmet.h | 15 +++++++++++++++ 3 files changed, 15 insertions(+), 20 deletions(-)
drivers/nvme/target/admin-cmd.c +0 -13
@@ -19,19 +19,6 @@#include <asm/unaligned.h> #include "nvmet.h" -/* -* This helper allows us to clear the AEN based on the RAE bit, -* Please use this helper when processing the log pages which are -* associated with the AEN. -*/ -static inline void nvmet_clear_aen (struct nvmet_req *req,u32 aen_bit) -{ -int rae =le32_to_cpu (req->cmd->common.cdw10[0 ]) &1 <<15 ; - -if (!rae) -clear_bit (aen_bit, &req->sq->ctrl->aen_masked); -} -u32 nvmet_get_log_page_len (struct nvme_command *cmd) {u32 len =le16_to_cpu (cmd->get_log_page.numdu);
drivers/nvme/target/core.c +0 -7
@@ -149,13 +149,6 @@ static void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,schedule_work (&ctrl->async_event_work); } -static bool nvmet_aen_disabled (struct nvmet_ctrl *ctrl,u32 aen) -{ -if (!(READ_ONCE (ctrl->aen_enabled) & aen)) -return true; -return test_and_set_bit (aen, &ctrl->aen_masked); -} -static void nvmet_add_to_changed_ns_log (struct nvmet_ctrl *ctrl,__le32 nsid) {u32 i;
drivers/nvme/target/nvmet.h +15 -0
@@ -324,6 +324,21 @@ struct nvmet_async_event {u8 log_page; }; +static inline void nvmet_clear_aen (struct nvmet_req *req,u32 aen_bit) +{ +int rae =le32_to_cpu (req->cmd->common.cdw10[0 ]) &1 <<15 ; + +if (!rae) +clear_bit (aen_bit, &req->sq->ctrl->aen_masked); +} + +static inline bool nvmet_aen_disabled (struct nvmet_ctrl *ctrl,u32 aen) +{ +if (!(READ_ONCE (ctrl->aen_enabled) & aen)) +return true; +return test_and_set_bit (aen, &ctrl->aen_masked); +} +u16 nvmet_parse_connect_cmd (struct nvmet_req *req);u16 nvmet_bdev_parse_io_cmd (struct nvmet_req *req);u16 nvmet_file_parse_io_cmd (struct nvmet_req *req);
Signature · 1 line
1.8.3.1
PATCH v2 1/11 nvmet: Provide aen bit functions for multiple controller types
Looks fine,
PATCH v2 2/11 nvmet: Change aen mask functions to use bit numbers
In reply to Jay SternbergFunctions nvmet_aen_disabled and nvmet_clear_aen were using values not bit numbers ie 1 << 9 not 9 for bit function clear_bit and test_and_set_bit.
---
v2 - unchanged
drivers/nvme/target/admin-cmd.c | 4 ++-- drivers/nvme/target/core.c | 4 ++-- drivers/nvme/target/nvmet.h | 10 +++++----- include/linux/nvme.h | 12 +++++++++--- 4 files changed, 18 insertions(+), 12 deletions(-)
drivers/nvme/target/admin-cmd.c +2 -2
@@ -176,7 +176,7 @@ static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req)if (!status) status =nvmet_zero_sgl (req, len, req->data_len - len); ctrl->nr_changed_ns =0 ; -nvmet_clear_aen (req,NVME_AEN_CFG_NS_ATTR ); +nvmet_clear_aen_bit (req,NVME_AEN_BIT_NS_ATTR );mutex_unlock (&ctrl->lock); out:nvmet_req_complete (req, status);
@@ -235,7 +235,7 @@ static void nvmet_execute_get_log_page_ana(struct nvmet_req *req) hdr.chgcnt =cpu_to_le64 (nvmet_ana_chgcnt); hdr.ngrps =cpu_to_le16 (ngrps); -nvmet_clear_aen (req,NVME_AEN_CFG_ANA_CHANGE ); +nvmet_clear_aen_bit (req,NVME_AEN_BIT_ANA_CHANGE );up_read (&nvmet_ana_sem);kfree (desc);
drivers/nvme/target/core.c +2 -2
@@ -179,7 +179,7 @@ void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid)list_for_each_entry (ctrl, &subsys->ctrls, subsys_entry) {nvmet_add_to_changed_ns_log (ctrl,cpu_to_le32 (nsid)); -if (nvmet_aen_disabled (ctrl,NVME_AEN_CFG_NS_ATTR )) +if (nvmet_aen_bit_disabled (ctrl,NVME_AEN_BIT_NS_ATTR ))continue ; nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, NVME_AER_NOTICE_NS_CHANGED,
@@ -196,7 +196,7 @@ void nvmet_send_ana_event(struct nvmet_subsys *subsys,list_for_each_entry (ctrl, &subsys->ctrls, subsys_entry) {if (port && ctrl->port != port)continue ; -if (nvmet_aen_disabled (ctrl,NVME_AEN_CFG_ANA_CHANGE )) +if (nvmet_aen_bit_disabled (ctrl,NVME_AEN_BIT_ANA_CHANGE ))continue ;nvmet_add_async_event (ctrl,NVME_AER_TYPE_NOTICE ,NVME_AER_NOTICE_ANA ,NVME_LOG_ANA );
drivers/nvme/target/nvmet.h +5 -5
@@ -324,19 +324,19 @@ struct nvmet_async_event {u8 log_page; }; -static inline void nvmet_clear_aen (struct nvmet_req *req,u32 aen_bit) +static inline void nvmet_clear_aen_bit (struct nvmet_req *req,u32 bn) {int rae =le32_to_cpu (req->cmd->common.cdw10[0 ]) &1 <<15 ;if (!rae) -clear_bit (aen_bit, &req->sq->ctrl->aen_masked); +clear_bit (bn, &req->sq->ctrl->aen_masked); } -static inline bool nvmet_aen_disabled (struct nvmet_ctrl *ctrl,u32 aen) +static inline bool nvmet_aen_bit_disabled (struct nvmet_ctrl *ctrl,u32 bn) { -if (!(READ_ONCE (ctrl->aen_enabled) & aen)) +if (!(READ_ONCE (ctrl->aen_enabled) &BIT (bn)))return true; -return test_and_set_bit (aen, &ctrl->aen_masked); +return test_and_set_bit (bn, &ctrl->aen_masked); }u16 nvmet_parse_connect_cmd (struct nvmet_req *req);
include/linux/nvme.h +9 -3
@@ -484,9 +484,15 @@ enum { };enum { -NVME_AEN_CFG_NS_ATTR =1 <<8 , -NVME_AEN_CFG_FW_ACT =1 <<9 , -NVME_AEN_CFG_ANA_CHANGE =1 <<11 , +NVME_AEN_BIT_NS_ATTR =8 , +NVME_AEN_BIT_FW_ACT =9 , +NVME_AEN_BIT_ANA_CHANGE =11 , +}; + +enum { +NVME_AEN_CFG_NS_ATTR =BIT (NVME_AEN_BIT_NS_ATTR ), +NVME_AEN_CFG_FW_ACT =BIT (NVME_AEN_BIT_FW_ACT ), +NVME_AEN_CFG_ANA_CHANGE =BIT (NVME_AEN_BIT_ANA_CHANGE ), };struct nvme_lba_range_type {
Signature · 1 line
1.8.3.1
PATCH v2 2/11 nvmet: Change aen mask functions to use bit numbers
Quoted 6 lines · Jay Sternberg
Functions
nvmet_aen_disabledandnvmet_clear_aenwere using values not bit numbers ie 1 << 9 not 9 for bit functionclear_bitandtest_and_set_bit.Signed-off-by Jay Sternberg <jay.e.sternberg at intel.com>Reviewed-by Phil Cayton <phil.cayton at intel.com>
Can you please explace the usage of the weird BIT() macro with the much more obvious 1 << bit as in the rest of the nvme code?
Otherwise looks fine:
PATCH v2 3/11 nvmet: Allow Keep Alive for Discovery controller
In reply to Jay SternbergPer change to specification allowing Discovery controllers to have explicit persistent connections, remove restriction on Discovery controllers allowing kato on connect.
---
v2 - unchanged
drivers/nvme/target/admin-cmd.c | 2 +- drivers/nvme/target/core.c | 36 ++++++++++-------------------------- drivers/nvme/target/discovery.c | 4 ++++ drivers/nvme/target/nvmet.h | 4 +++- 4 files changed, 18 insertions(+), 28 deletions(-)
drivers/nvme/target/admin-cmd.c +1 -1
@@ -721,7 +721,7 @@ static void nvmet_execute_async_event(struct nvmet_req *req)schedule_work (&ctrl->async_event_work); } -static void nvmet_execute_keep_alive (struct nvmet_req *req) +void nvmet_execute_keep_alive (struct nvmet_req *req) {struct nvmet_ctrl *ctrl = req->sq->ctrl;
drivers/nvme/target/core.c +10 -26
@@ -990,31 +990,17 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, ctrl->cntlid = ret; ctrl->ops = req->ops; -if (ctrl->subsys->type ==NVME_NQN_DISC ) { -/* Don't accept keep-alive timeout for discovery controllers */ -if (kato) { - status =NVME_SC_INVALID_FIELD |NVME_SC_DNR ; - goto out_remove_ida; - } -/* -* Discovery controllers use some arbitrary high value in order -* to cleanup stale discovery sessions -* -* From the latest base diff RC: -* "The Keep Alive command is not supported by -* Discovery controllers. A transport may specify a -* fixed Discovery controller activity timeout value -* (e.g., 2 minutes). If no commands are received -* by a Discovery controller within that time -* period, the controller may perform the -* actions for Keep Alive Timer expiration". -*/ - ctrl->kato =NVMET_DISC_KATO ; - }else { -/* keep-alive timeout in seconds */ - ctrl->kato =DIV_ROUND_UP (kato,1000 ); - } +/* +* Discovery controllers may use some arbitrary high value +* in order to cleanup stale discovery sessions +*/ +if ((ctrl->subsys->type ==NVME_NQN_DISC ) && !kato) + kato =NVMET_DISC_KATO ; + +/* keep-alive timeout in seconds */ + ctrl->kato =DIV_ROUND_UP (kato,1000 ); +nvmet_start_keep_alive_timer (ctrl);mutex_lock (&subsys->lock);
@@ -1024,8 +1010,6 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, *ctrlp = ctrl;return 0 ; -out_remove_ida: -ida_simple_remove (&cntlid_ida, ctrl->cntlid); out_free_sqs:kfree (ctrl->sqs); out_free_cqs:
drivers/nvme/target/discovery.c +4 -0
@@ -194,6 +194,10 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req) }switch (cmd->common.opcode) { +case nvme_admin_keep_alive: + req->execute = nvmet_execute_keep_alive; + req->data_len =0 ; +return 0 ;case nvme_admin_get_log_page: req->data_len =nvmet_get_log_page_len (cmd);
drivers/nvme/target/nvmet.h +3 -1
@@ -352,6 +352,8 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,void nvmet_req_execute (struct nvmet_req *req);void nvmet_req_complete (struct nvmet_req *req,u16 status); +void nvmet_execute_keep_alive (struct nvmet_req *req); +void nvmet_cq_setup (struct nvmet_ctrl *ctrl,struct nvmet_cq *cq,u16 qid,u16 size); void nvmet_sq_setup(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, u16 qid,
@@ -422,7 +424,7 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf,#define NVMET_DEFAULT_ANA_GRPID 1#define NVMET_KAS 10 -#define NVMET_DISC_KATO 120 +#define NVMET_DISC_KATO 120000/* ms */ int __init nvmet_init_configfs (void ); void __exit nvmet_exit_configfs(void);
Signature · 1 line
1.8.3.1
PATCH v2 3/11 nvmet: Allow Keep Alive for Discovery controller
drivers/nvme/target/core.c u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, · line 999
Quoted 2 lines
drivers/nvme/target/core.c +2
-0+if ((ctrl->subsys->type ==NVME_NQN_DISC ) && !kato) + kato =NVMET_DISC_KATO ;
No need for the inner braces here.
Quoted 1 line
+#define
NVMET_DISC_KATO120000 /* ms */
I'd rename it to NVMET_DISC_KATO_MS to make the unit obvious and remove the need for the comment.
Otherwise looks fine:
PATCH v2 4/11 nvmet: Make kato and AEN processing for use by other controllers
In reply to Jay SternbergMake common process of get/set features available to other controllers by making simple functions static inline and others not static and prototypes in nvmet.h file
Also remove static from nvmet_execute_async_event and add prototype to nvmet.h to allow used by other controllers
---
v2 - unchanged
drivers/nvme/target/admin-cmd.c | 44 +++++++++++++++++++++++++++-------------- drivers/nvme/target/nvmet.h | 14 +++++++++++++ 2 files changed, 43 insertions(+), 15 deletions(-)
drivers/nvme/target/admin-cmd.c +29 -15
@@ -582,11 +582,34 @@ static u16 nvmet_set_feat_write_protect(struct nvmet_req *req)return status; } +u16 nvmet_set_feat_kato (struct nvmet_req *req) +{ +u32 val32 =le32_to_cpu (req->cmd->common.cdw10[1 ]); + + req->sq->ctrl->kato =DIV_ROUND_UP (val32,1000 ); + +nvmet_set_result (req, req->sq->ctrl->kato); + +return 0 ; +} + +u16 nvmet_set_feat_async_event (struct nvmet_req *req,u32 mask) +{ +u32 val32 =le32_to_cpu (req->cmd->common.cdw10[1 ]); + +if (val32 & ~mask) +return NVME_SC_INVALID_FIELD |NVME_SC_DNR ; + +WRITE_ONCE (req->sq->ctrl->aen_enabled, val32); +nvmet_set_result (req, val32); + +return 0 ; +} +static void nvmet_execute_set_features (struct nvmet_req *req) {struct nvmet_subsys *subsys = req->sq->ctrl->subsys;u32 cdw10 =le32_to_cpu (req->cmd->common.cdw10[0 ]); -u32 val32;u16 status =0 ;switch (cdw10 &0xff ) {
@@ -595,19 +618,10 @@ static void nvmet_execute_set_features(struct nvmet_req *req) (subsys->max_qid - 1) | ((subsys->max_qid - 1) << 16));break ;case NVME_FEAT_KATO : - val32 =le32_to_cpu (req->cmd->common.cdw10[1 ]); - req->sq->ctrl->kato =DIV_ROUND_UP (val32,1000 ); -nvmet_set_result (req, req->sq->ctrl->kato); + status =nvmet_set_feat_kato (req);break ;case NVME_FEAT_ASYNC_EVENT : - val32 =le32_to_cpu (req->cmd->common.cdw10[1 ]); -if (val32 & ~NVMET_AEN_CFG_ALL ) { - status =NVME_SC_INVALID_FIELD |NVME_SC_DNR ; -break ; - } - -WRITE_ONCE (req->sq->ctrl->aen_enabled, val32); -nvmet_set_result (req, val32); + status =nvmet_set_feat_async_event (req,NVMET_AEN_CFG_ALL );break ;case NVME_FEAT_HOST_ID : status =NVME_SC_CMD_SEQ_ERROR |NVME_SC_DNR ;
@@ -672,7 +686,7 @@ static void nvmet_execute_get_features(struct nvmet_req *req)break ;#endif case NVME_FEAT_ASYNC_EVENT : -nvmet_set_result (req,READ_ONCE (req->sq->ctrl->aen_enabled)); +nvmet_get_feat_async_event (req);break ;case NVME_FEAT_VOLATILE_WC :nvmet_set_result (req,1 );
@@ -682,7 +696,7 @@ static void nvmet_execute_get_features(struct nvmet_req *req) (subsys->max_qid-1) | ((subsys->max_qid-1) << 16));break ;case NVME_FEAT_KATO : -nvmet_set_result (req, req->sq->ctrl->kato *1000 ); +nvmet_get_feat_kato (req);break ;case NVME_FEAT_HOST_ID :/* need 128-bit host identifier flag */
@@ -705,7 +719,7 @@ static void nvmet_execute_get_features(struct nvmet_req *req)nvmet_req_complete (req, status); } -static void nvmet_execute_async_event (struct nvmet_req *req) +void nvmet_execute_async_event (struct nvmet_req *req) {struct nvmet_ctrl *ctrl = req->sq->ctrl;
drivers/nvme/target/nvmet.h +14 -0
@@ -339,6 +339,20 @@ static inline bool nvmet_aen_bit_disabled(struct nvmet_ctrl *ctrl, u32 bn)return test_and_set_bit (bn, &ctrl->aen_masked); } +static inline void nvmet_get_feat_kato (struct nvmet_req *req) +{ +nvmet_set_result (req, req->sq->ctrl->kato *1000 ); +} + +static inline void nvmet_get_feat_async_event (struct nvmet_req *req) +{ +nvmet_set_result (req,READ_ONCE (req->sq->ctrl->aen_enabled)); +} + +u16 nvmet_set_feat_kato (struct nvmet_req *req); +u16 nvmet_set_feat_async_event (struct nvmet_req *req,u32 mask); +void nvmet_execute_async_event (struct nvmet_req *req); +u16 nvmet_parse_connect_cmd (struct nvmet_req *req);u16 nvmet_bdev_parse_io_cmd (struct nvmet_req *req);u16 nvmet_file_parse_io_cmd (struct nvmet_req *req);
Signature · 1 line
1.8.3.1
PATCH v2 4/11 nvmet: Make kato and AEN processing for use by other controllers
Quoted 6 lines · Jay Sternberg
Make common process of get/set features available to other controllers by making simple functions static inline and others not static and prototypes in
nvmet.hfileAlso remove static from
nvmet_execute_async_eventand add prototype tonvmet.hto allow used by other controllers
I'd move nvmet_get_feat_kato and nvmet_get_feat_async_event out of line, just to not bloat the header with too much random sprinkled implementation bits, given none of this is timing critical.
Otherwise looks good:
PATCH v2 5/11 nvmet: Add defines for discovery change async events
In reply to Jay SternbergAdd AEN/AER values as defined by the specification
---
v2 - unchanged
drivers/nvme/target/nvmet.h | 2 ++ include/linux/nvme.h | 3 +++ 2 files changed, 5 insertions(+)
drivers/nvme/target/nvmet.h +2 -0
@@ -35,6 +35,8 @@*/ #define NVMET_AEN_CFG_OPTIONAL \ (NVME_AEN_CFG_NS_ATTR | NVME_AEN_CFG_ANA_CHANGE) +#define NVMET_DISC_AEN_CFG_OPTIONAL \ + (NVME_AEN_CFG_DISC_CHANGE)/* * Plus mandatory SMART AENs (we'll never send them, but allow enabling them):
include/linux/nvme.h +3 -0
@@ -481,18 +481,21 @@ enum {NVME_AER_NOTICE_NS_CHANGED =0x00 ,NVME_AER_NOTICE_FW_ACT_STARTING =0x01 ,NVME_AER_NOTICE_ANA =0x03 , + NVME_AER_NOTICE_DISC_CHANGED = 0xf0, };enum {NVME_AEN_BIT_NS_ATTR =8 ,NVME_AEN_BIT_FW_ACT =9 ,NVME_AEN_BIT_ANA_CHANGE =11 , +NVME_AEN_BIT_DISC_CHANGE =31 , };enum {NVME_AEN_CFG_NS_ATTR =BIT (NVME_AEN_BIT_NS_ATTR ),NVME_AEN_CFG_FW_ACT =BIT (NVME_AEN_BIT_FW_ACT ),NVME_AEN_CFG_ANA_CHANGE =BIT (NVME_AEN_BIT_ANA_CHANGE ), +NVME_AEN_CFG_DISC_CHANGE =BIT (NVME_AEN_BIT_DISC_CHANGE ), }; struct nvme_lba_range_type {
Signature · 1 line
1.8.3.1
PATCH v2 5/11 nvmet: Add defines for discovery change async events
Looks good,
PATCH v2 5/11 nvmet: Add defines for discovery change async events
In reply to Jay SternbergQuoted 1 line · Jay Sternberg
Add AEN/AER values as defined by the specification
Looks good,
PATCH v2 6/11 nvmet: Add support to Discovery controllers for commands
In reply to Jay SternbergAdd custom get/set features to restrict commands allowed by Discovery controllers.
---
v2 - unchanged
drivers/nvme/target/discovery.c | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
drivers/nvme/target/discovery.c +53 -0
@@ -183,6 +183,47 @@ static void nvmet_execute_identify_disc_ctrl(struct nvmet_req *req)nvmet_req_complete (req, status); } +static void nvmet_execute_disc_set_features (struct nvmet_req *req) +{ +u32 cdw10 =le32_to_cpu (req->cmd->common.cdw10[0 ]); +u16 stat; + +switch (cdw10 &0xff ) { +case NVME_FEAT_KATO : + stat =nvmet_set_feat_kato (req); +break ; +case NVME_FEAT_ASYNC_EVENT : + stat =nvmet_set_feat_async_event (req, +NVMET_DISC_AEN_CFG_OPTIONAL ); +break ; +default : + stat =NVME_SC_INVALID_FIELD |NVME_SC_DNR ; +break ; + } + +nvmet_req_complete (req, stat); +} + +static void nvmet_execute_disc_get_features (struct nvmet_req *req) +{ +u32 cdw10 =le32_to_cpu (req->cmd->common.cdw10[0 ]); +u16 stat =0 ; + +switch (cdw10 &0xff ) { +case NVME_FEAT_KATO : +nvmet_get_feat_kato (req); +break ; +case NVME_FEAT_ASYNC_EVENT : +nvmet_get_feat_async_event (req); +break ; +default : + stat =NVME_SC_INVALID_FIELD |NVME_SC_DNR ; +break ; + } + +nvmet_req_complete (req, stat); +} +u16 nvmet_parse_discovery_cmd (struct nvmet_req *req) {struct nvme_command *cmd = req->cmd;
@@ -194,6 +235,18 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req) }switch (cmd->common.opcode) { +case nvme_admin_set_features: + req->execute = nvmet_execute_disc_set_features; + req->data_len =0 ; +return 0 ; +case nvme_admin_get_features: + req->execute = nvmet_execute_disc_get_features; + req->data_len =0 ; +return 0 ; +case nvme_admin_async_event: + req->execute = nvmet_execute_async_event; + req->data_len =0 ; +return 0 ;case nvme_admin_keep_alive: req->execute = nvmet_execute_keep_alive; req->data_len =0 ;
Signature · 1 line
1.8.3.1
PATCH v2 6/11 nvmet: Add support to Discovery controllers for commands
Quoted 2 lines · Jay Sternberg
Add custom get/set features to restrict commands allowed by Discovery controllers.
This does't restrict anything, but actually adds the previously unimplemented commands, doesn't it?
Otherwise looks good:
PATCH v2 7/11 nvmet: Add parent to nvmet_referral_disable
In reply to Jay SternbergTo be used when Discovery Change notifications occur
---
v2 - unchanged
drivers/nvme/target/configfs.c | 5 +++-- drivers/nvme/target/discovery.c | 2 +- drivers/nvme/target/nvmet.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-)
drivers/nvme/target/configfs.c +3 -2
@@ -889,7 +889,7 @@ static ssize_t nvmet_referral_enable_store(struct config_item *item,if (enable)nvmet_referral_enable (parent, port);else -nvmet_referral_disable (port); +nvmet_referral_disable (parent, port);return count; inval:
@@ -915,9 +915,10 @@ static ssize_t nvmet_referral_enable_store(struct config_item *item,static void nvmet_referral_release (struct config_item *item) { +struct nvmet_port *parent =to_nvmet_port (item->ci_parent->ci_parent);struct nvmet_port *port =to_nvmet_port (item); -nvmet_referral_disable (port); +nvmet_referral_disable (parent, port);kfree (port); }
drivers/nvme/target/discovery.c +1 -1
@@ -31,7 +31,7 @@ void nvmet_referral_enable(struct nvmet_port *parent, struct nvmet_port *port)up_write (&nvmet_config_sem); } -void nvmet_referral_disable (struct nvmet_port *port) +void nvmet_referral_disable (struct nvmet_port *parent,struct nvmet_port *port) {down_write (&nvmet_config_sem);if (!list_empty (&port->entry)) {
drivers/nvme/target/nvmet.h +1 -1
@@ -410,7 +410,7 @@ void nvmet_send_ana_event(struct nvmet_subsys *subsys,void nvmet_disable_port (struct nvmet_port *port);void nvmet_referral_enable (struct nvmet_port *parent,struct nvmet_port *port); -void nvmet_referral_disable (struct nvmet_port *port); +void nvmet_referral_disable (struct nvmet_port *parent,struct nvmet_port *port);u16 nvmet_copy_to_sgl (struct nvmet_req *req,off_t off,const void *buf,size_t len);
Signature · 1 line
1.8.3.1
PATCH v2 7/11 nvmet: Add parent to nvmet_referral_disable
Quoted 1 line · Jay Sternberg
To be used when Discovery Change notifications occur
Looks fine, but I'd be tempted to just merge this into the patch actually using it.
PATCH v2 8/11 nvmet: Maintain a global list of ports
In reply to Jay SternbergTo be used when Discovery Change notifications occur
---
v2 - unchanged
drivers/nvme/target/configfs.c | 7 +++++++ drivers/nvme/target/nvmet.h | 3 +++ 2 files changed, 10 insertions(+)
drivers/nvme/target/configfs.c +7 -0
@@ -23,6 +23,9 @@static const struct config_item_type nvmet_host_type;static const struct config_item_type nvmet_subsys_type; +static LIST_HEAD (nvmet_ports_list); +struct list_head *nvmet_ports = &nvmet_ports_list; + static const struct nvmet_transport_name { u8 type; const char *name;
@@ -1091,6 +1094,8 @@ static void nvmet_port_release(struct config_item *item) {struct nvmet_port *port =to_nvmet_port (item); +list_del (&port->global_entry); +kfree (port->ana_state);kfree (port); }
@@ -1143,6 +1148,8 @@ static struct config_group *nvmet_ports_make(struct config_group *group, port->ana_state[i] =NVME_ANA_INACCESSIBLE ; } +list_add (&port->global_entry, &nvmet_ports_list); +INIT_LIST_HEAD (&port->entry);INIT_LIST_HEAD (&port->subsystems);INIT_LIST_HEAD (&port->referrals);
drivers/nvme/target/nvmet.h +3 -0
@@ -130,6 +130,7 @@ struct nvmet_port {struct list_head subsystems;struct config_group referrals_group;struct list_head referrals; +struct list_head global_entry;struct config_group ana_groups_group;struct nvmet_ana_group ana_default_group;enum nvme_ana_state *ana_state;
@@ -420,6 +421,8 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf,u32 nvmet_get_log_page_len (struct nvme_command *cmd); +extern struct list_head *nvmet_ports; +#define NVMET_QUEUE_SIZE 1024#define NVMET_NR_QUEUES 128#define NVMET_MAX_CMD NVMET_QUEUE_SIZE
Signature · 1 line
1.8.3.1
PATCH v2 8/11 nvmet: Maintain a global list of ports
Quoted 1 line · Jay Sternberg
To be used when Discovery Change notifications occur
Looks fine, but again I'm tempted to move this into the patch actually using the information.
PATCH v2 9/11 nvmet: allow host connect even if no allowed
In reply to Jay SternbergFrom: Sagi Grimberg <[email protected]>
It is perfectly valid that a host connects to a discovery subsystem and gets an empty discovery log page since no subsystems are provisioned to it. No reason to disallow connecting to the discovery subsystem all together.
---
v2 - corrected author and updated description per authors request
drivers/nvme/target/core.c | 20 +++----------------- drivers/nvme/target/discovery.c | 2 +- drivers/nvme/target/nvmet.h | 3 +-- 3 files changed, 5 insertions(+), 20 deletions(-)
drivers/nvme/target/core.c +3 -17
@@ -890,26 +890,12 @@ static bool __nvmet_host_allowed(struct nvmet_subsys *subsys,return false; } -static bool nvmet_host_discovery_allowed (struct nvmet_req *req, -const char *hostnqn) -{ -struct nvmet_subsys_link *s; - -list_for_each_entry (s, &req->port->subsystems, entry) { -if (__nvmet_host_allowed (s->subsys, hostnqn)) -return true; - } - -return false; -} - -bool nvmet_host_allowed (struct nvmet_req *req,struct nvmet_subsys *subsys, -const char *hostnqn) +bool nvmet_host_allowed (struct nvmet_subsys *subsys,const char *hostnqn) {lockdep_assert_held (&nvmet_config_sem);if (subsys->type ==NVME_NQN_DISC ) -return nvmet_host_discovery_allowed (req, hostnqn); +return true;else return __nvmet_host_allowed (subsys, hostnqn); }
@@ -933,7 +919,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, status =NVME_SC_CONNECT_INVALID_PARAM |NVME_SC_DNR ;down_read (&nvmet_config_sem); -if (!nvmet_host_allowed (req, subsys, hostnqn)) { +if (!nvmet_host_allowed (subsys, hostnqn)) {pr_info ("connect by host %s for subsystem %s not allowed\n" , hostnqn, subsysnqn); req->rsp->result.u32 =IPO_IATTR_CONNECT_DATA (hostnqn);
drivers/nvme/target/discovery.c +1 -1
@@ -107,7 +107,7 @@ static void nvmet_execute_get_disc_log_page(struct nvmet_req *req)down_read (&nvmet_config_sem);list_for_each_entry (p, &req->port->subsystems, entry) { -if (!nvmet_host_allowed (req, p->subsys, ctrl->hostnqn)) +if (!nvmet_host_allowed (p->subsys, ctrl->hostnqn))continue ;if (residual_len >= entry_size) {char traddr[NVMF_TRADDR_SIZE ];
drivers/nvme/target/nvmet.h +1 -2
@@ -459,8 +459,7 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf,extern u64 nvmet_ana_chgcnt;extern struct rw_semaphore nvmet_ana_sem; -bool nvmet_host_allowed (struct nvmet_req *req,struct nvmet_subsys *subsys, -const char *hostnqn); +bool nvmet_host_allowed (struct nvmet_subsys *subsys,const char *hostnqn);int nvmet_bdev_ns_enable (struct nvmet_ns *ns);int nvmet_file_ns_enable (struct nvmet_ns *ns);
Signature · 1 line
1.8.3.1
PATCH v2 9/11 nvmet: allow host connect even if no allowed
drivers/nvme/target/core.c static bool __nvmet_host_allowed(struct nvmet_subsys *subsys, · line 900
Quoted 9 lines
drivers/nvme/target/core.c +2
-1+bool nvmet_host_allowed (struct nvmet_subsys *subsys,const char *hostnqn) {lockdep_assert_held (&nvmet_config_sem);if (subsys->type ==NVME_NQN_DISC ) -return nvmet_host_discovery_allowed (req, hostnqn); +return true;else return __nvmet_host_allowed (subsys, hostnqn);
Please merge __nvmet_host_allowed into nvmet_host_allowed, with an early return for the NVME_NQN_DISC case. Please also write a comment explaining that special case.
PATCH v2 10/11 nvmet: Provide adding AENs for multiple controller types
In reply to Jay SternbergFrom: Phil Cayton <[email protected]>
Make nvmet_add_async_event a non-static function in preparation for use by other controllers, initally the discovery controller.
---
v2 - unchanged
drivers/nvme/target/core.c | 2 +- drivers/nvme/target/nvmet.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/nvme/target/core.c +1 -1
@@ -129,7 +129,7 @@ static void nvmet_async_event_work(struct work_struct *work) } } -static void nvmet_add_async_event (struct nvmet_ctrl *ctrl,u8 event_type, +void nvmet_add_async_event (struct nvmet_ctrl *ctrl,u8 event_type,u8 event_info,u8 log_page) {struct nvmet_async_event *aen;
drivers/nvme/target/nvmet.h +2 -0
@@ -422,6 +422,8 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf,u32 nvmet_get_log_page_len (struct nvme_command *cmd);extern struct list_head *nvmet_ports; +void nvmet_add_async_event (struct nvmet_ctrl *ctrl,u8 event_type, +u8 event_info,u8 log_page);#define NVMET_QUEUE_SIZE 1024#define NVMET_NR_QUEUES 128
Signature · 1 line
1.8.3.1
PATCH v2 10/11 nvmet: Provide adding AENs for multiple controller types
Quoted 4 lines · Jay Sternberg
From: Phil Cayton <phil.cayton at intel.com>
Make
nvmet_add_async_eventa non-static function in preparation for use by other controllers, initally the discovery controller.
Looks fine, but please merge it into the patch actually using the feature.
PATCH v2 11/11 nvmet: Enable Discovery Controller AENs
In reply to Jay SternbergAdd functions to find connections requesting Discovery Change events and send a notification to hosts that maintain an explicit persistent connection and have and active Asynchronous Event Request pending. Only Hosts that have access to the Subsystem effected by the change will receive notifications of Discovery Change event.
Call these functions each time there is a configfs change that effects the Discover Log Pages.
Set the OAES field in the Identify Controller response to advertise the support for Asynchronous Event Notifications.
---
v2 - updated commit description
drivers/nvme/target/configfs.c | 14 +++++++++- drivers/nvme/target/discovery.c | 60 +++++++++++++++++++++++++++++++++++++++++ drivers/nvme/target/nvmet.h | 4 +++ 3 files changed, 77 insertions(+), 1 deletion(-)
drivers/nvme/target/configfs.c +13 -1
@@ -603,6 +603,8 @@ static int nvmet_port_subsys_allow_link(struct config_item *parent,list_add_tail (&link->entry, &port->subsystems); nvmet_genctr++; +nvmet_port_disc_change_event (port, subsys); +up_write (&nvmet_config_sem);return 0 ;
@@ -630,6 +632,8 @@ static void nvmet_port_subsys_drop_link(struct config_item *parent, found:list_del (&p->entry); nvmet_genctr++; +nvmet_port_disc_change_event (port, subsys); +if (list_empty (&port->subsystems))nvmet_disable_port (port);up_write (&nvmet_config_sem);
@@ -679,6 +683,8 @@ static int nvmet_allowed_hosts_allow_link(struct config_item *parent, }list_add_tail (&link->entry, &subsys->hosts); nvmet_genctr++; +nvmet_subsys_disc_change_event (subsys, host); +up_write (&nvmet_config_sem);return 0 ; out_free_link:
@@ -705,6 +711,8 @@ static void nvmet_allowed_hosts_drop_link(struct config_item *parent, found:list_del (&p->entry); nvmet_genctr++; +nvmet_subsys_disc_change_event (subsys, host); +up_write (&nvmet_config_sem);kfree (p); }
@@ -743,7 +751,11 @@ static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item, goto out_unlock; } - subsys->allow_any_host = allow_any_host; +if (subsys->allow_any_host != allow_any_host) { + subsys->allow_any_host = allow_any_host; +nvmet_subsys_disc_change_event (subsys,NULL ); + } + out_unlock:up_write (&nvmet_config_sem);return ret ? ret : count;
drivers/nvme/target/discovery.c +60 -0
90 lines not on this page · raw message
drivers/nvme/target/nvmet.h +4 -0
@@ -422,6 +422,10 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf,u32 nvmet_get_log_page_len (struct nvme_command *cmd);extern struct list_head *nvmet_ports; +void nvmet_port_disc_change_event (struct nvmet_port *port, +struct nvmet_subsys *subsys); +void nvmet_subsys_disc_change_event (struct nvmet_subsys *subsys, +struct nvmet_host *host);void nvmet_add_async_event (struct nvmet_ctrl *ctrl,u8 event_type,u8 event_info,u8 log_page);
Signature · 1 line
1.8.3.1
PATCH v2 11/11 nvmet: Enable Discovery Controller AENs
drivers/nvme/target/configfs.c static int nvmet_port_subsys_allow_link(struct config_item *parent, · line 606
Quoted 3 lines
drivers/nvme/target/configfs.c +1
-0list_add_tail (&link->entry, &port->subsystems); nvmet_genctr++; +nvmet_port_disc_change_event (port, subsys);
It seems like the increment of nvmet_genctr should move into nvmet_port_disc_change_event / nvmet_subsys_disc_change_event.
I'd also name these functions similar to the namespace event handler, e.g. nvmet_port_disc_changed / nvmet_subsys_disc_changed.
Sagi Grimberg
maintainerv2 cover nvmet: Enable AENs support for Discovery controllers
In reply to Jay SternbergFor any patch in this series that doesn't already have it,
Christoph, Keith, any feedback from you guys?
Christoph Hellwig
maintainerv2 cover nvmet: Enable AENs support for Discovery controllers
Quoted 5 lines · Sagi Grimberg
For any patch in this series that doesn't already have it,
Reviewed-by Sagi Grimberg <sagi at grimberg.me>Christoph, Keith, any feedback from you guys?
This mail comes out of nowhere without a previous thread here.
Sagi Grimberg
maintainerv2 cover nvmet: Enable AENs support for Discovery controllers
Quoted 8 lines
Quoted 6 lines
For any patch in this series that doesn't already have it,
Reviewed-by Sagi Grimberg <sagi at grimberg.me>Christoph, Keith, any feedback from you guys?
This mail comes out of nowhere without a previous thread here.
Umm, Jay sent two revisions of this patch set.
http://lists.infradead.org/pipermail/linux-nvme/2018-October/020232.html
http://lists.infradead.org/pipermail/linux-nvme/2018-October/020426.html