[PATH libnvme v1 2/2] fabrics: Do not pass disable_sqflow if not supported

Daniel Wagner dwagner at suse.de
Tue Jul 25 01:41:37 PDT 2023


Only retry a connect attempt with disable_sqflow if the kernel
actually supports this option.

Reported-by: Sagi Grimberg <sagi at grimberg.me>
Signed-off-by: Daniel Wagner <dwagner at suse.de>
---
 src/nvme/fabrics.c | 85 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 1 deletion(-)

diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c
index 2f26c2b7f39a..e2953e7ef2a4 100644
--- a/src/nvme/fabrics.c
+++ b/src/nvme/fabrics.c
@@ -227,6 +227,32 @@ static const struct nvme_fabric_options default_options = {
 	.trsvcid = true,
 };
 
+static const char *default_options_strings[] =
+{
+	"ctrl_loss_tmo",
+	"data_digest",
+	"disable_sqflow",
+	"discovery",
+	"duplicate_connect",
+	"fast_io_fail_tmo",
+	"hdr_digest",
+	"host_iface",
+	"host_traddr",
+	"hostid",
+	"hostnqn",
+	"keep_alive_tmo",
+	"nqn",
+	"nr_io_queues",
+	"nr_poll_queues",
+	"nr_write_queues",
+	"queue_size",
+	"reconnect_delay",
+	"tos",
+	"traddr",
+	"transport",
+	"trsvcid",
+};
+
 void nvmf_default_config(struct nvme_fabrics_config *cfg)
 {
 	memset(cfg, 0, sizeof(*cfg));
@@ -652,6 +678,62 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr)
 		continue;		   \
 	}
 
+static bool nvme_check_default_option(const char *opt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(default_options_strings); i++) {
+		if (!strcmp(opt, default_options_strings[i]))
+			return true;
+	}
+	return false;
+}
+
+static bool nvmf_check_option(const char *opt)
+{
+	char buf[0x1000], *options, *p, *v;
+	ssize_t len;
+	int fd;
+	bool supported = false;
+
+	fd = open(nvmf_dev, O_RDONLY);
+	if (fd < 0)
+		return false;
+
+	len = read(fd, buf, sizeof(buf) - 1);
+	if (len < 0) {
+		if (errno == EINVAL) {
+			/*
+			 * Older Linux kernels don't allow reading from nvmf_dev
+			 * to get supported options, so use a default set
+			 */
+			supported = nvme_check_default_option(opt);
+		}
+
+		goto out_close;
+	}
+
+	buf[len] = '\0';
+	options = buf;
+	while ((p = strsep(&options, ",\n")) != NULL) {
+		if (!*p)
+			continue;
+		v = strsep(&p, "= ");
+		if (!v)
+			continue;
+
+		if (strcmp(opt, v))
+			continue;
+
+		supported = true;
+		break;
+	}
+
+out_close:
+	close(fd);
+	return supported;
+}
+
 static int nvmf_read_options(nvme_root_t r)
 {
 	char buf[0x1000], *options, *p, *v;
@@ -1038,7 +1120,8 @@ nvme_ctrl_t nvmf_connect_disc_entry(nvme_host_t h,
 	if (!ret)
 		return c;
 
-	if (errno == EINVAL && c->cfg.disable_sqflow) {
+	if (errno == EINVAL && c->cfg.disable_sqflow &&
+	    nvmf_check_option("disable_sqflow")) {
 		errno = 0;
 		/* disable_sqflow is unrecognized option on older kernels */
 		nvme_msg(h->r, LOG_INFO, "failed to connect controller, "
-- 
2.41.0




More information about the Linux-nvme mailing list