Message ID | 20200327171545.98970-16-maxg@mellanox.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Series | nvme-rdma/nvmet-rdma: Add metadata/T10-PI support | expand |
> + /* > + * Max command capsule size is sqe + single page of in-capsule data. > + * Disable inline data for Metadata capable controllers. > + */ > id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) + > - req->port->inline_data_size) / 16); > + req->port->inline_data_size * > + !ctrl->pi_support) / 16); Can we de-obsfucated this a little? cmd_capsule_size = sizeof(struct nvme_command); if (!ctrl->pi_support) cmd_capsule_size += req->port->inline_data_size; id->ioccsz = cpu_to_le32(cmd_capsule_size / 16); > + if (ctrl->subsys->pi_support && ctrl->port->pi_enable) { > + if (ctrl->port->pi_capable) { > + ctrl->pi_support = true; > + pr_info("controller %d T10-PI enabled\n", ctrl->cntlid); > + } else { > + ctrl->pi_support = false; > + pr_warn("T10-PI is not supported on controller %d\n", > + ctrl->cntlid); > + } I think the printks are a little verbose. Also why can we set ctrl->port->pi_enable if ctrl->port->pi_capable is false? Shoudn't we reject that earlier? In that case this could simply become: ctrl->pi_support = ctrl->subsys->pi_support && ctrl->port->pi_enable; > +#ifdef CONFIG_BLK_DEV_INTEGRITY > +static inline u32 nvmet_rw_md_len(struct nvmet_req *req) > +{ > + return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) * req->ns->ms; > +} > + > +static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns) > +{ > + return ns->md_type && ns->ms == sizeof(struct t10_pi_tuple); > +} > +#else > +static inline u32 nvmet_rw_md_len(struct nvmet_req *req) > +{ > + return 0; Do we really need a stub for nvmet_rw_md_len? Also for nvmet_ns_has_pi we could probably reword it as: static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns) { if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY)) return false; return ns->pi_type && ns->metadata_size == sizeof(struct t10_pi_tuple); } and avoid the need for a stub as well.
On 4/21/2020 6:30 PM, Christoph Hellwig wrote: >> + /* >> + * Max command capsule size is sqe + single page of in-capsule data. >> + * Disable inline data for Metadata capable controllers. >> + */ >> id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) + >> - req->port->inline_data_size) / 16); >> + req->port->inline_data_size * >> + !ctrl->pi_support) / 16); > Can we de-obsfucated this a little? > > cmd_capsule_size = sizeof(struct nvme_command); > if (!ctrl->pi_support) > cmd_capsule_size += req->port->inline_data_size; > id->ioccsz = cpu_to_le32(cmd_capsule_size / 16); Yes good idea. > >> + if (ctrl->subsys->pi_support && ctrl->port->pi_enable) { >> + if (ctrl->port->pi_capable) { >> + ctrl->pi_support = true; >> + pr_info("controller %d T10-PI enabled\n", ctrl->cntlid); >> + } else { >> + ctrl->pi_support = false; >> + pr_warn("T10-PI is not supported on controller %d\n", >> + ctrl->cntlid); >> + } > I think the printks are a little verbose. Also why can we set > ctrl->port->pi_enable if ctrl->port->pi_capable is false? Shoudn't > we reject that earlier? In that case this could simply become: > > ctrl->pi_support = ctrl->subsys->pi_support && ctrl->port->pi_enable; for that we'll need to check pi_capable during add_port process and disable pi_enable bit if user set it. User should set it before enable the port (this will always succeed). I'll make this change as well. re the verbosity, sometimes I get many requests from users to get indication for some features. We can remove this as well if needed. >> +#ifdef CONFIG_BLK_DEV_INTEGRITY >> +static inline u32 nvmet_rw_md_len(struct nvmet_req *req) >> +{ >> + return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) * req->ns->ms; >> +} >> + >> +static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns) >> +{ >> + return ns->md_type && ns->ms == sizeof(struct t10_pi_tuple); >> +} >> +#else >> +static inline u32 nvmet_rw_md_len(struct nvmet_req *req) >> +{ >> + return 0; > Do we really need a stub for nvmet_rw_md_len? Also for nvmet_ns_has_pi > we could probably reword it as: > > static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns) > { > if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY)) > return false; > return ns->pi_type && ns->metadata_size == sizeof(struct t10_pi_tuple); > } > > and avoid the need for a stub as well. yup.
On Thu, Apr 23, 2020 at 03:39:38PM +0300, Max Gurtovoy wrote: >>> + if (ctrl->subsys->pi_support && ctrl->port->pi_enable) { >>> + if (ctrl->port->pi_capable) { >>> + ctrl->pi_support = true; >>> + pr_info("controller %d T10-PI enabled\n", ctrl->cntlid); >>> + } else { >>> + ctrl->pi_support = false; >>> + pr_warn("T10-PI is not supported on controller %d\n", >>> + ctrl->cntlid); >>> + } >> I think the printks are a little verbose. Also why can we set >> ctrl->port->pi_enable if ctrl->port->pi_capable is false? Shoudn't >> we reject that earlier? In that case this could simply become: >> >> ctrl->pi_support = ctrl->subsys->pi_support && ctrl->port->pi_enable; > > for that we'll need to check pi_capable during add_port process and disable > pi_enable bit if user set it. Which seems pretty sensible. In fact I think the configfs write for pi enable should fail if we don't have the capability. > User should set it before enable the port (this will always succeed). > > I'll make this change as well. > > re the verbosity, sometimes I get many requests from users to get > indication for some features. > > We can remove this as well if needed. I'd rather keep debug prints silent. You could add a verbose mode in nvmetcli that prints all the settings applied if that helps these users.
On 4/24/2020 10:14 AM, Christoph Hellwig wrote: > On Thu, Apr 23, 2020 at 03:39:38PM +0300, Max Gurtovoy wrote: >>>> + if (ctrl->subsys->pi_support && ctrl->port->pi_enable) { >>>> + if (ctrl->port->pi_capable) { >>>> + ctrl->pi_support = true; >>>> + pr_info("controller %d T10-PI enabled\n", ctrl->cntlid); >>>> + } else { >>>> + ctrl->pi_support = false; >>>> + pr_warn("T10-PI is not supported on controller %d\n", >>>> + ctrl->cntlid); >>>> + } >>> I think the printks are a little verbose. Also why can we set >>> ctrl->port->pi_enable if ctrl->port->pi_capable is false? Shoudn't >>> we reject that earlier? In that case this could simply become: >>> >>> ctrl->pi_support = ctrl->subsys->pi_support && ctrl->port->pi_enable; >> for that we'll need to check pi_capable during add_port process and disable >> pi_enable bit if user set it. > Which seems pretty sensible. In fact I think the configfs write for > pi enable should fail if we don't have the capability. The port is not enabled so it's not possible currently. But we can disable it afterwards (in nvmet_enable_port) : + /* If the transport didn't set pi_capable, then disable it. */ + if (!port->pi_capable) + port->pi_enable = false; > >> User should set it before enable the port (this will always succeed). >> >> I'll make this change as well. >> >> re the verbosity, sometimes I get many requests from users to get >> indication for some features. >> >> We can remove this as well if needed. > I'd rather keep debug prints silent. You could add a verbose mode > in nvmetcli that prints all the settings applied if that helps these > users. how about: - pr_info("creating controller %d for subsystem %s for NQN %s.\n", - ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn); + pr_info("creating controller %d for subsystem %s for NQN %s%s.\n", + ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn, + ctrl->pi_support ? " T10-PI is enabled" : "");
On Sun, Apr 26, 2020 at 01:50:05PM +0300, Max Gurtovoy wrote: >>>> I think the printks are a little verbose. Also why can we set >>>> ctrl->port->pi_enable if ctrl->port->pi_capable is false? Shoudn't >>>> we reject that earlier? In that case this could simply become: >>>> >>>> ctrl->pi_support = ctrl->subsys->pi_support && ctrl->port->pi_enable; >>> for that we'll need to check pi_capable during add_port process and disable >>> pi_enable bit if user set it. >> Which seems pretty sensible. In fact I think the configfs write for >> pi enable should fail if we don't have the capability. > > The port is not enabled so it's not possible currently. > > But we can disable it afterwards (in nvmet_enable_port) : > > + /* If the transport didn't set pi_capable, then disable it. */ > + if (!port->pi_capable) > + port->pi_enable = false; I don't think we should allow users to enable invalid configurations and silently clear flags, but reject flags as soon as we can - write to the attribute where possible, else during enable. > how about: > > - pr_info("creating controller %d for subsystem %s for NQN %s.\n", > - ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn); > + pr_info("creating controller %d for subsystem %s for NQN %s%s.\n", > + ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn, > + ctrl->pi_support ? " T10-PI is enabled" : ""); Ok.
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 24ed5b2..8a2c059 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -432,9 +432,13 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) strlcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn)); - /* Max command capsule size is sqe + single page of in-capsule data */ + /* + * Max command capsule size is sqe + single page of in-capsule data. + * Disable inline data for Metadata capable controllers. + */ id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) + - req->port->inline_data_size) / 16); + req->port->inline_data_size * + !ctrl->pi_support) / 16); /* Max response capsule size is cqe */ id->iorcsz = cpu_to_le32(sizeof(struct nvme_completion) / 16); @@ -464,6 +468,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) static void nvmet_execute_identify_ns(struct nvmet_req *req) { + struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvmet_ns *ns; struct nvme_id_ns *id; u16 status = 0; @@ -520,6 +525,16 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req) id->lbaf[0].ds = ns->blksize_shift; + if (ctrl->pi_support && nvmet_ns_has_pi(ns)) { + id->dpc = NVME_NS_DPC_PI_FIRST | NVME_NS_DPC_PI_LAST | + NVME_NS_DPC_PI_TYPE1 | NVME_NS_DPC_PI_TYPE2 | + NVME_NS_DPC_PI_TYPE3; + id->mc = NVME_NS_MC_META_EXT; + id->dps = ns->md_type; + id->flbas = NVME_NS_FLBAS_META_EXT; + id->lbaf[0].ms = ns->ms; + } + if (ns->readonly) id->nsattr |= (1 << 0); nvmet_put_namespace(ns); diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 7aa1078..19bf240 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -248,6 +248,36 @@ static ssize_t nvmet_param_inline_data_size_store(struct config_item *item, CONFIGFS_ATTR(nvmet_, param_inline_data_size); +#ifdef CONFIG_BLK_DEV_INTEGRITY +static ssize_t nvmet_param_pi_enable_show(struct config_item *item, + char *page) +{ + struct nvmet_port *port = to_nvmet_port(item); + + return snprintf(page, PAGE_SIZE, "%d\n", port->pi_enable); +} + +static ssize_t nvmet_param_pi_enable_store(struct config_item *item, + const char *page, size_t count) +{ + struct nvmet_port *port = to_nvmet_port(item); + bool val; + + if (strtobool(page, &val)) + return -EINVAL; + + if (port->enabled) { + pr_err("Disable port before setting pi_enable value.\n"); + return -EACCES; + } + + port->pi_enable = val; + return count; +} + +CONFIGFS_ATTR(nvmet_, param_pi_enable); +#endif + static ssize_t nvmet_addr_trtype_show(struct config_item *item, char *page) { @@ -987,6 +1017,31 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item, } CONFIGFS_ATTR(nvmet_subsys_, attr_model); +#ifdef CONFIG_BLK_DEV_INTEGRITY +static ssize_t nvmet_subsys_attr_pi_enable_show(struct config_item *item, + char *page) +{ + return snprintf(page, PAGE_SIZE, "%d\n", to_subsys(item)->pi_support); +} + +static ssize_t nvmet_subsys_attr_pi_enable_store(struct config_item *item, + const char *page, size_t count) +{ + struct nvmet_subsys *subsys = to_subsys(item); + bool pi_enable; + + if (strtobool(page, &pi_enable)) + return -EINVAL; + + down_write(&nvmet_config_sem); + subsys->pi_support = pi_enable; + up_write(&nvmet_config_sem); + + return count; +} +CONFIGFS_ATTR(nvmet_subsys_, attr_pi_enable); +#endif + static struct configfs_attribute *nvmet_subsys_attrs[] = { &nvmet_subsys_attr_attr_allow_any_host, &nvmet_subsys_attr_attr_version, @@ -994,6 +1049,9 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item, &nvmet_subsys_attr_attr_cntlid_min, &nvmet_subsys_attr_attr_cntlid_max, &nvmet_subsys_attr_attr_model, +#ifdef CONFIG_BLK_DEV_INTEGRITY + &nvmet_subsys_attr_attr_pi_enable, +#endif NULL, }; @@ -1289,6 +1347,9 @@ static void nvmet_port_release(struct config_item *item) &nvmet_attr_addr_trsvcid, &nvmet_attr_addr_trtype, &nvmet_attr_param_inline_data_size, +#ifdef CONFIG_BLK_DEV_INTEGRITY + &nvmet_attr_param_pi_enable, +#endif NULL, }; diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index 52a6f70..799de18 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -197,6 +197,17 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) goto out; } + if (ctrl->subsys->pi_support && ctrl->port->pi_enable) { + if (ctrl->port->pi_capable) { + ctrl->pi_support = true; + pr_info("controller %d T10-PI enabled\n", ctrl->cntlid); + } else { + ctrl->pi_support = false; + pr_warn("T10-PI is not supported on controller %d\n", + ctrl->cntlid); + } + } + uuid_copy(&ctrl->hostid, &d->hostid); status = nvmet_install_queue(ctrl, req); diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index e7954d9..b976aad 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -145,6 +145,8 @@ struct nvmet_port { bool enabled; int inline_data_size; const struct nvmet_fabrics_ops *tr_ops; + bool pi_capable; + bool pi_enable; }; static inline struct nvmet_port *to_nvmet_port(struct config_item *item) @@ -204,6 +206,7 @@ struct nvmet_ctrl { spinlock_t error_lock; u64 err_counter; struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS]; + bool pi_support; }; struct nvmet_subsys_model { @@ -233,6 +236,7 @@ struct nvmet_subsys { u64 ver; u64 serial; char *subsysnqn; + bool pi_support; struct config_group group; @@ -513,6 +517,28 @@ static inline u32 nvmet_rw_data_len(struct nvmet_req *req) req->ns->blksize_shift; } +#ifdef CONFIG_BLK_DEV_INTEGRITY +static inline u32 nvmet_rw_md_len(struct nvmet_req *req) +{ + return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) * req->ns->ms; +} + +static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns) +{ + return ns->md_type && ns->ms == sizeof(struct t10_pi_tuple); +} +#else +static inline u32 nvmet_rw_md_len(struct nvmet_req *req) +{ + return 0; +} + +static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns) +{ + return false; +} +#endif /* CONFIG_BLK_DEV_INTEGRITY */ + static inline u32 nvmet_dsm_len(struct nvmet_req *req) { return (le32_to_cpu(req->cmd->dsm.nr) + 1) *