* [PATCH v3 1/4] nvmet: support fabrics sq flow control
2018-11-14 18:25 [PATCH v3 0/4] Support SQ flow control disabled mode (TP 8005) Sagi Grimberg
@ 2018-11-14 18:25 ` Sagi Grimberg
2018-11-15 11:40 ` Christoph Hellwig
2018-11-14 18:25 ` [PATCH v3 2/4] nvmet: don't override treq upon modification Sagi Grimberg
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Sagi Grimberg @ 2018-11-14 18:25 UTC (permalink / raw)
Technical proposal 8005 "fabrics SQ flow control" introduces a mode
where a host and controller agree to omit sq_head pointer updates
when sending nvme completions.
In case the host indicated desire to operate in this mode (connect attribute)
the controller will return back a connect completion with sq_head value
of 0xffff as indication that it will omit sq_head pointer updates.
This mode saves us an atomic update in the I/O path.
Reviewed-by: Hannes Reinecke <hare at suse.com>
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
drivers/nvme/target/core.c | 21 ++++++++++++++-------
drivers/nvme/target/fabrics-cmd.c | 8 +++++++-
drivers/nvme/target/nvmet.h | 3 ++-
include/linux/nvme.h | 4 ++++
4 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index e3e158ff207a..9240b0a245a1 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -597,15 +597,12 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
return ns;
}
-static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
+static void nvmet_update_sq_head(struct nvmet_req *req)
{
u32 old_sqhd, new_sqhd;
u16 sqhd;
- if (status)
- nvmet_set_status(req, status);
-
- if (req->sq->size) {
+ if (!req->sq->sqhd_disabled && req->sq->size) {
do {
old_sqhd = req->sq->sqhd;
new_sqhd = (old_sqhd + 1) % req->sq->size;
@@ -614,9 +611,18 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
}
sqhd = req->sq->sqhd & 0x0000FFFF;
req->rsp->sq_head = cpu_to_le16(sqhd);
+}
+
+static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
+{
+ if (status)
+ nvmet_set_status(req, status);
+
req->rsp->sq_id = cpu_to_le16(req->sq->qid);
req->rsp->command_id = req->cmd->common.command_id;
+ nvmet_update_sq_head(req);
+
if (req->ns)
nvmet_put_namespace(req->ns);
req->ops->queue_response(req);
@@ -639,9 +645,10 @@ void nvmet_cq_setup(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq,
}
void nvmet_sq_setup(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq,
- u16 qid, u16 size)
+ u16 qid, u16 size, bool sqhd_disabled)
{
- sq->sqhd = 0;
+ sq->sqhd_disabled = sqhd_disabled;
+ sq->sqhd = sq->sqhd_disabled ? 0xffff : 0;
sq->qid = qid;
sq->size = size;
diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c
index d84ae004cb85..1f05d8507e35 100644
--- a/drivers/nvme/target/fabrics-cmd.c
+++ b/drivers/nvme/target/fabrics-cmd.c
@@ -114,7 +114,9 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
/* note: convert queue size from 0's-based value to 1's-based value */
nvmet_cq_setup(ctrl, req->cq, qid, sqsize + 1);
- nvmet_sq_setup(ctrl, req->sq, qid, sqsize + 1);
+ nvmet_sq_setup(ctrl, req->sq, qid, sqsize + 1,
+ !!(c->cattr & NVME_CONNECT_DISABLE_SQFLOW));
+
return 0;
}
@@ -173,6 +175,8 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)
kfree(d);
complete:
nvmet_req_complete(req, status);
+ if (req->sq->sqhd_disabled)
+ req->sq->sqhd = 0;
}
static void nvmet_execute_io_connect(struct nvmet_req *req)
@@ -229,6 +233,8 @@ static void nvmet_execute_io_connect(struct nvmet_req *req)
kfree(d);
complete:
nvmet_req_complete(req, status);
+ if (req->sq->sqhd_disabled)
+ req->sq->sqhd = 0;
return;
out_ctrl_put:
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 31474940e373..613a37683eae 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -106,6 +106,7 @@ struct nvmet_sq {
u16 qid;
u16 size;
u32 sqhd;
+ bool sqhd_disabled;
struct completion free_done;
struct completion confirm_done;
};
@@ -386,7 +387,7 @@ 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,
- u16 size);
+ u16 size, bool sqhd_disabled);
void nvmet_sq_destroy(struct nvmet_sq *sq);
int nvmet_sq_init(struct nvmet_sq *sq);
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 77d320d32ee5..e7d731776f62 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -1044,6 +1044,10 @@ struct nvmf_disc_rsp_page_hdr {
struct nvmf_disc_rsp_page_entry entries[0];
};
+enum {
+ NVME_CONNECT_DISABLE_SQFLOW = (1 << 2),
+};
+
struct nvmf_connect_command {
__u8 opcode;
__u8 resv1;
--
2.17.1
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v3 1/4] nvmet: support fabrics sq flow control
2018-11-14 18:25 ` [PATCH v3 1/4] nvmet: support fabrics sq flow control Sagi Grimberg
@ 2018-11-15 11:40 ` Christoph Hellwig
2018-11-15 17:31 ` Sagi Grimberg
0 siblings, 1 reply; 12+ messages in thread
From: Christoph Hellwig @ 2018-11-15 11:40 UTC (permalink / raw)
> complete:
> nvmet_req_complete(req, status);
> + if (req->sq->sqhd_disabled)
> + req->sq->sqhd = 0;
We drop the sq ref in nvmet_req_complete, so this introduces a
use-after-free. What about this variant instead:
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index e3e158ff207a..74e253eb873f 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -597,25 +597,29 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
return ns;
}
-static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
+static void nvmet_update_sq_head(struct nvmet_req *req)
{
- u32 old_sqhd, new_sqhd;
- u16 sqhd;
-
- if (status)
- nvmet_set_status(req, status);
-
if (req->sq->size) {
+ u32 old_sqhd, new_sqhd;
+
do {
old_sqhd = req->sq->sqhd;
new_sqhd = (old_sqhd + 1) % req->sq->size;
} while (cmpxchg(&req->sq->sqhd, old_sqhd, new_sqhd) !=
old_sqhd);
}
- sqhd = req->sq->sqhd & 0x0000FFFF;
- req->rsp->sq_head = cpu_to_le16(sqhd);
+
+ req->rsp->sq_head = cpu_to_le16(req->sq->sqhd & 0x0000FFFF);
+}
+
+static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
+{
+ if (!req->sq->sqhd_disabled)
+ nvmet_update_sq_head(req);
req->rsp->sq_id = cpu_to_le16(req->sq->qid);
req->rsp->command_id = req->cmd->common.command_id;
+ if (status)
+ nvmet_set_status(req, status);
if (req->ns)
nvmet_put_namespace(req->ns);
@@ -765,6 +769,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
req->sg_cnt = 0;
req->transfer_len = 0;
req->rsp->status = 0;
+ req->rsp->sq_head = 0;
req->ns = NULL;
/* no support for fused commands yet */
diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c
index d84ae004cb85..328ae46d8344 100644
--- a/drivers/nvme/target/fabrics-cmd.c
+++ b/drivers/nvme/target/fabrics-cmd.c
@@ -115,6 +115,12 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
/* note: convert queue size from 0's-based value to 1's-based value */
nvmet_cq_setup(ctrl, req->cq, qid, sqsize + 1);
nvmet_sq_setup(ctrl, req->sq, qid, sqsize + 1);
+
+ if (c->cattr & NVME_CONNECT_DISABLE_SQFLOW) {
+ req->sq->sqhd_disabled = true;
+ req->rsp->sq_head = cpu_to_le16(0xffff);
+ }
+
return 0;
}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 31474940e373..ab8e68966e73 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -106,6 +106,7 @@ struct nvmet_sq {
u16 qid;
u16 size;
u32 sqhd;
+ bool sqhd_disabled;
struct completion free_done;
struct completion confirm_done;
};
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 77d320d32ee5..e7d731776f62 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -1044,6 +1044,10 @@ struct nvmf_disc_rsp_page_hdr {
struct nvmf_disc_rsp_page_entry entries[0];
};
+enum {
+ NVME_CONNECT_DISABLE_SQFLOW = (1 << 2),
+};
+
struct nvmf_connect_command {
__u8 opcode;
__u8 resv1;
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v3 1/4] nvmet: support fabrics sq flow control
2018-11-15 11:40 ` Christoph Hellwig
@ 2018-11-15 17:31 ` Sagi Grimberg
0 siblings, 0 replies; 12+ messages in thread
From: Sagi Grimberg @ 2018-11-15 17:31 UTC (permalink / raw)
> We drop the sq ref in nvmet_req_complete, so this introduces a
> use-after-free. What about this variant instead:
That is definitely better. I'll give it a test drive.
>
> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
> index e3e158ff207a..74e253eb873f 100644
> --- a/drivers/nvme/target/core.c
> +++ b/drivers/nvme/target/core.c
> @@ -597,25 +597,29 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
> return ns;
> }
>
> -static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
> +static void nvmet_update_sq_head(struct nvmet_req *req)
> {
> - u32 old_sqhd, new_sqhd;
> - u16 sqhd;
> -
> - if (status)
> - nvmet_set_status(req, status);
> -
> if (req->sq->size) {
> + u32 old_sqhd, new_sqhd;
> +
> do {
> old_sqhd = req->sq->sqhd;
> new_sqhd = (old_sqhd + 1) % req->sq->size;
> } while (cmpxchg(&req->sq->sqhd, old_sqhd, new_sqhd) !=
> old_sqhd);
> }
> - sqhd = req->sq->sqhd & 0x0000FFFF;
> - req->rsp->sq_head = cpu_to_le16(sqhd);
> +
> + req->rsp->sq_head = cpu_to_le16(req->sq->sqhd & 0x0000FFFF);
> +}
> +
> +static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
> +{
> + if (!req->sq->sqhd_disabled)
> + nvmet_update_sq_head(req);
> req->rsp->sq_id = cpu_to_le16(req->sq->qid);
> req->rsp->command_id = req->cmd->common.command_id;
> + if (status)
> + nvmet_set_status(req, status);
>
> if (req->ns)
> nvmet_put_namespace(req->ns);
> @@ -765,6 +769,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
> req->sg_cnt = 0;
> req->transfer_len = 0;
> req->rsp->status = 0;
> + req->rsp->sq_head = 0;
> req->ns = NULL;
>
> /* no support for fused commands yet */
> diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c
> index d84ae004cb85..328ae46d8344 100644
> --- a/drivers/nvme/target/fabrics-cmd.c
> +++ b/drivers/nvme/target/fabrics-cmd.c
> @@ -115,6 +115,12 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
> /* note: convert queue size from 0's-based value to 1's-based value */
> nvmet_cq_setup(ctrl, req->cq, qid, sqsize + 1);
> nvmet_sq_setup(ctrl, req->sq, qid, sqsize + 1);
> +
> + if (c->cattr & NVME_CONNECT_DISABLE_SQFLOW) {
> + req->sq->sqhd_disabled = true;
> + req->rsp->sq_head = cpu_to_le16(0xffff);
> + }
> +
> return 0;
> }
>
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 31474940e373..ab8e68966e73 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -106,6 +106,7 @@ struct nvmet_sq {
> u16 qid;
> u16 size;
> u32 sqhd;
> + bool sqhd_disabled;
> struct completion free_done;
> struct completion confirm_done;
> };
> diff --git a/include/linux/nvme.h b/include/linux/nvme.h
> index 77d320d32ee5..e7d731776f62 100644
> --- a/include/linux/nvme.h
> +++ b/include/linux/nvme.h
> @@ -1044,6 +1044,10 @@ struct nvmf_disc_rsp_page_hdr {
> struct nvmf_disc_rsp_page_entry entries[0];
> };
>
> +enum {
> + NVME_CONNECT_DISABLE_SQFLOW = (1 << 2),
> +};
> +
> struct nvmf_connect_command {
> __u8 opcode;
> __u8 resv1;
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 2/4] nvmet: don't override treq upon modification.
2018-11-14 18:25 [PATCH v3 0/4] Support SQ flow control disabled mode (TP 8005) Sagi Grimberg
2018-11-14 18:25 ` [PATCH v3 1/4] nvmet: support fabrics sq flow control Sagi Grimberg
@ 2018-11-14 18:25 ` Sagi Grimberg
2018-11-15 11:40 ` Christoph Hellwig
2018-11-14 18:25 ` [PATCH v3 3/4] nvmet: expose support for fabrics SQ flow control disable in treq Sagi Grimberg
` (2 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Sagi Grimberg @ 2018-11-14 18:25 UTC (permalink / raw)
Only override the allowed parts of it.
Reviewed-by: Hannes Reinecke <hare at suse.com>
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
drivers/nvme/target/configfs.c | 11 +++++++----
drivers/nvme/target/nvmet.h | 2 ++
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index d37fd7713bbc..a98ab935b537 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -153,7 +153,8 @@ CONFIGFS_ATTR(nvmet_, addr_traddr);
static ssize_t nvmet_addr_treq_show(struct config_item *item,
char *page)
{
- switch (to_nvmet_port(item)->disc_addr.treq) {
+ switch (to_nvmet_port(item)->disc_addr.treq &
+ NVMET_TREQ_SECURE_CHANNEL_MASK) {
case NVMF_TREQ_NOT_SPECIFIED:
return sprintf(page, "not specified\n");
case NVMF_TREQ_REQUIRED:
@@ -169,6 +170,7 @@ static ssize_t nvmet_addr_treq_store(struct config_item *item,
const char *page, size_t count)
{
struct nvmet_port *port = to_nvmet_port(item);
+ u8 treq = port->disc_addr.treq & ~NVMET_TREQ_SECURE_CHANNEL_MASK;
if (port->enabled) {
pr_err("Cannot modify address while enabled\n");
@@ -177,15 +179,16 @@ static ssize_t nvmet_addr_treq_store(struct config_item *item,
}
if (sysfs_streq(page, "not specified")) {
- port->disc_addr.treq = NVMF_TREQ_NOT_SPECIFIED;
+ treq |= NVMF_TREQ_NOT_SPECIFIED;
} else if (sysfs_streq(page, "required")) {
- port->disc_addr.treq = NVMF_TREQ_REQUIRED;
+ treq |= NVMF_TREQ_REQUIRED;
} else if (sysfs_streq(page, "not required")) {
- port->disc_addr.treq = NVMF_TREQ_NOT_REQUIRED;
+ treq |= NVMF_TREQ_NOT_REQUIRED;
} else {
pr_err("Invalid value '%s' for treq\n", page);
return -EINVAL;
}
+ port->disc_addr.treq = treq;
return count;
}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 613a37683eae..abc603fa725d 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -56,6 +56,8 @@
#define IPO_IATTR_CONNECT_SQE(x) \
(cpu_to_le32(offsetof(struct nvmf_connect_command, x)))
+#define NVMET_TREQ_SECURE_CHANNEL_MASK 0x3
+
struct nvmet_ns {
struct list_head dev_link;
struct percpu_ref ref;
--
2.17.1
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v3 2/4] nvmet: don't override treq upon modification.
2018-11-14 18:25 ` [PATCH v3 2/4] nvmet: don't override treq upon modification Sagi Grimberg
@ 2018-11-15 11:40 ` Christoph Hellwig
2018-11-15 17:32 ` Sagi Grimberg
0 siblings, 1 reply; 12+ messages in thread
From: Christoph Hellwig @ 2018-11-15 11:40 UTC (permalink / raw)
> index 613a37683eae..abc603fa725d 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -56,6 +56,8 @@
> #define IPO_IATTR_CONNECT_SQE(x) \
> (cpu_to_le32(offsetof(struct nvmf_connect_command, x)))
>
> +#define NVMET_TREQ_SECURE_CHANNEL_MASK 0x3
Shouldn't this go with the other NVMET_TREQ_ symbols in the enum?
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 2/4] nvmet: don't override treq upon modification.
2018-11-15 11:40 ` Christoph Hellwig
@ 2018-11-15 17:32 ` Sagi Grimberg
0 siblings, 0 replies; 12+ messages in thread
From: Sagi Grimberg @ 2018-11-15 17:32 UTC (permalink / raw)
>> index 613a37683eae..abc603fa725d 100644
>> --- a/drivers/nvme/target/nvmet.h
>> +++ b/drivers/nvme/target/nvmet.h
>> @@ -56,6 +56,8 @@
>> #define IPO_IATTR_CONNECT_SQE(x) \
>> (cpu_to_le32(offsetof(struct nvmf_connect_command, x)))
>>
>> +#define NVMET_TREQ_SECURE_CHANNEL_MASK 0x3
>
> Shouldn't this go with the other NVMET_TREQ_ symbols in the enum?
You mean NVME_TREQ_ enum in nvme.h, I can place it there, but probably
still as a define as it is a mask and not an enumeration.
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 3/4] nvmet: expose support for fabrics SQ flow control disable in treq
2018-11-14 18:25 [PATCH v3 0/4] Support SQ flow control disabled mode (TP 8005) Sagi Grimberg
2018-11-14 18:25 ` [PATCH v3 1/4] nvmet: support fabrics sq flow control Sagi Grimberg
2018-11-14 18:25 ` [PATCH v3 2/4] nvmet: don't override treq upon modification Sagi Grimberg
@ 2018-11-14 18:25 ` Sagi Grimberg
2018-11-14 18:25 ` [PATCH v3 4/4] nvme: disable fabrics SQ flow control when asked by the user Sagi Grimberg
2018-11-14 18:25 ` [PATCH v3 nvme-cli 5/4] fabrics: support fabrics sq flow control disable Sagi Grimberg
4 siblings, 0 replies; 12+ messages in thread
From: Sagi Grimberg @ 2018-11-14 18:25 UTC (permalink / raw)
Technical Proposal introduces an indication for SQ flow control
disable support. Expose it since we are able to operate in this mode.
Reviewed-by: Hannes Reinecke <hare at suse.com>
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
drivers/nvme/target/configfs.c | 1 +
include/linux/nvme.h | 7 ++++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index a98ab935b537..c2df205096ec 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -1214,6 +1214,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
port->inline_data_size = -1; /* < 0 == let the transport choose */
port->disc_addr.portid = cpu_to_le16(portid);
+ port->disc_addr.treq = NVMF_TREQ_DISABLE_SQFLOW;
config_group_init_type_name(&port->group, name, &nvmet_port_type);
config_group_init_type_name(&port->subsys_group,
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index e7d731776f62..4a560ea04d7c 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -58,9 +58,10 @@ enum {
/* Transport Requirements codes for Discovery Log Page entry TREQ field */
enum {
- NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */
- NVMF_TREQ_REQUIRED = 1, /* Required */
- NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */
+ NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */
+ NVMF_TREQ_REQUIRED = 1, /* Required */
+ NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */
+ NVMF_TREQ_DISABLE_SQFLOW = (1 << 2), /* Supports SQ flow control disable */
};
/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
--
2.17.1
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v3 4/4] nvme: disable fabrics SQ flow control when asked by the user
2018-11-14 18:25 [PATCH v3 0/4] Support SQ flow control disabled mode (TP 8005) Sagi Grimberg
` (2 preceding siblings ...)
2018-11-14 18:25 ` [PATCH v3 3/4] nvmet: expose support for fabrics SQ flow control disable in treq Sagi Grimberg
@ 2018-11-14 18:25 ` Sagi Grimberg
2018-11-15 11:40 ` Christoph Hellwig
2018-11-14 18:25 ` [PATCH v3 nvme-cli 5/4] fabrics: support fabrics sq flow control disable Sagi Grimberg
4 siblings, 1 reply; 12+ messages in thread
From: Sagi Grimberg @ 2018-11-14 18:25 UTC (permalink / raw)
As for now, we don't care about sq_head pointer updates anyway, so
at least allow the controller to micro-optimize by omiting this update.
Note that we will probably need to support it when a controller
that requires this comes along.
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
drivers/nvme/host/fabrics.c | 13 +++++++++++++
drivers/nvme/host/fabrics.h | 2 ++
2 files changed, 15 insertions(+)
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index bd0969db6225..b78d1a674abc 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -392,6 +392,9 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
cmd.connect.kato = ctrl->opts->discovery_nqn ? 0 :
cpu_to_le32((ctrl->kato + NVME_KATO_GRACE) * 1000);
+ if (ctrl->opts->disable_sqflow)
+ cmd.connect.cattr |= NVME_CONNECT_DISABLE_SQFLOW;
+
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -451,6 +454,9 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid)
cmd.connect.qid = cpu_to_le16(qid);
cmd.connect.sqsize = cpu_to_le16(ctrl->sqsize);
+ if (ctrl->opts->disable_sqflow)
+ cmd.connect.cattr |= NVME_CONNECT_DISABLE_SQFLOW;
+
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -607,6 +613,7 @@ static const match_table_t opt_tokens = {
{ NVMF_OPT_HOST_TRADDR, "host_traddr=%s" },
{ NVMF_OPT_HOST_ID, "hostid=%s" },
{ NVMF_OPT_DUP_CONNECT, "duplicate_connect" },
+ { NVMF_OPT_DISABLE_SQFLOW, "disable_sqflow" },
{ NVMF_OPT_ERR, NULL }
};
@@ -817,6 +824,9 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
case NVMF_OPT_DUP_CONNECT:
opts->duplicate_connect = true;
break;
+ case NVMF_OPT_DISABLE_SQFLOW:
+ opts->disable_sqflow = true;
+ break;
default:
pr_warn("unknown parameter or missing value '%s' in ctrl creation request\n",
p);
@@ -901,6 +911,9 @@ EXPORT_SYMBOL_GPL(nvmf_ip_options_match);
static int nvmf_check_allowed_opts(struct nvmf_ctrl_options *opts,
unsigned int allowed_opts)
{
+ /* fabrics parameter, allowed regardless of the transport */
+ allowed_opts |= NVMF_OPT_DISABLE_SQFLOW;
+
if (opts->mask & ~allowed_opts) {
int i;
diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h
index 6ea6275f332a..ecd9a006a091 100644
--- a/drivers/nvme/host/fabrics.h
+++ b/drivers/nvme/host/fabrics.h
@@ -58,6 +58,7 @@ enum {
NVMF_OPT_CTRL_LOSS_TMO = 1 << 11,
NVMF_OPT_HOST_ID = 1 << 12,
NVMF_OPT_DUP_CONNECT = 1 << 13,
+ NVMF_OPT_DISABLE_SQFLOW = 1 << 14,
};
/**
@@ -101,6 +102,7 @@ struct nvmf_ctrl_options {
unsigned int kato;
struct nvmf_host *host;
int max_reconnects;
+ bool disable_sqflow;
};
/*
--
2.17.1
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v3 nvme-cli 5/4] fabrics: support fabrics sq flow control disable
2018-11-14 18:25 [PATCH v3 0/4] Support SQ flow control disabled mode (TP 8005) Sagi Grimberg
` (3 preceding siblings ...)
2018-11-14 18:25 ` [PATCH v3 4/4] nvme: disable fabrics SQ flow control when asked by the user Sagi Grimberg
@ 2018-11-14 18:25 ` Sagi Grimberg
4 siblings, 0 replies; 12+ messages in thread
From: Sagi Grimberg @ 2018-11-14 18:25 UTC (permalink / raw)
If the discovery log entry indicates that the subsystem supports
disabling sq flow control, we ask the host to connect and disable
sq flow control (omit sq_head pointer updates). Also add an option
to explicitly ask for disable_sqflow.
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
fabrics.c | 15 ++++++++++++++-
linux/nvme.h | 7 ++++---
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/fabrics.c b/fabrics.c
index 711a755a79e1..f6b060607b26 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -60,6 +60,7 @@ static struct config {
char *raw;
char *device;
int duplicate_connect;
+ int disable_sqflow;
} cfg = { NULL };
#define BUF_SIZE 4096
@@ -129,6 +130,8 @@ static const char * const treqs[] = {
[NVMF_TREQ_NOT_SPECIFIED] = "not specified",
[NVMF_TREQ_REQUIRED] = "required",
[NVMF_TREQ_NOT_REQUIRED] = "not required",
+ [NVMF_TREQ_DISABLE_SQFLOW] = "not specified, "
+ "sq flow control disable supported",
};
static inline const char *treq_str(__u8 treq)
@@ -595,7 +598,9 @@ static int build_options(char *argstr, int max_len)
add_int_argument(&argstr, &max_len, "ctrl_loss_tmo",
cfg.ctrl_loss_tmo) ||
add_bool_argument(&argstr, &max_len, "duplicate_connect",
- cfg.duplicate_connect))
+ cfg.duplicate_connect) ||
+ add_bool_argument(&argstr, &max_len, "disable_sqflow",
+ cfg.disable_sqflow))
return -EINVAL;
return 0;
@@ -732,6 +737,13 @@ static int connect_ctrl(struct nvmf_disc_rsp_page_entry *e)
return -EINVAL;
}
+ if (e->treq & NVMF_TREQ_DISABLE_SQFLOW) {
+ len = sprintf(p, ",disable_sqflow");
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
if (discover)
return do_discover(argstr, true);
else
@@ -935,6 +947,7 @@ int connect(const char *desc, int argc, char **argv)
{"reconnect-delay", 'c', "LIST", CFG_INT, &cfg.reconnect_delay, required_argument, "reconnect timeout period in seconds" },
{"ctrl-loss-tmo", 'l', "LIST", CFG_INT, &cfg.ctrl_loss_tmo, required_argument, "controller loss timeout period in seconds" },
{"duplicate_connect", 'D', "", CFG_NONE, &cfg.duplicate_connect, no_argument, "allow duplicate connections between same transport host and subsystem port" },
+ {"disable_sqflow", 'd', "", CFG_NONE, &cfg.disable_sqflow, no_argument, "disable controller sq flow control (default false)" },
{NULL},
};
diff --git a/linux/nvme.h b/linux/nvme.h
index 1ad970a4c89a..a6a44b066267 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -58,9 +58,10 @@ enum {
/* Transport Requirements codes for Discovery Log Page entry TREQ field */
enum {
- NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */
- NVMF_TREQ_REQUIRED = 1, /* Required */
- NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */
+ NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */
+ NVMF_TREQ_REQUIRED = 1, /* Required */
+ NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */
+ NVMF_TREQ_DISABLE_SQFLOW = (1 << 2), /* SQ flow control disable supported */
};
/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
--
2.17.1
^ permalink raw reply related [flat|nested] 12+ messages in thread