]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
fabrics: handle /dev/nvme-fabrics read failure
authorCaleb Sander <csander@purestorage.com>
Fri, 12 May 2023 00:40:26 +0000 (18:40 -0600)
committerDaniel Wagner <wagi@monom.org>
Mon, 15 May 2023 14:43:46 +0000 (16:43 +0200)
The ability to read from /dev/nvme-fabrics to find supported options
is a newer Linux kernel feature added in f18ee3d988157 (5.17-rc1).
On earlier kernels, this read returns EINVAL,
preventing the controller from being added:
$ nvme discover --transport tcp --traddr 192.168.1.62
Failed to read from /dev/nvme-fabrics: Invalid argument
failed to add controller, error Invalid argument

So don't treat EINVAL as a fatal error, and instead fall back
to a default set of supported options.
With this change, controllers can be created successfully:
$ nvme discover --transport tcp --traddr 192.168.1.62

Discovery Log Number of Records 4, Generation counter 125
...

Fixes: d123131f2e ("fabrics: Do not pass unsupported options to kernel")
Signed-off-by: Caleb Sander <csander@purestorage.com>
src/nvme/fabrics.c

index cb2dd0d22bdc68c919fac1d5d213948db229b0f8..176289816b9e78aed56551e5dc967a6b7f852a46 100644 (file)
@@ -196,6 +196,37 @@ const char *nvmf_cms_str(__u8 cm)
        return arg_str(cms, ARRAY_SIZE(cms), cm);
 }
 
+/*
+ * Derived from Linux's supported options (the opt_tokens table)
+ * when the mechanism to report supported options was added (f18ee3d988157).
+ * Not all of these options may actually be supported,
+ * but we retain the old behavior of passing all that might be.
+ */
+static const struct nvme_fabric_options default_supported_options = {
+       .ctrl_loss_tmo = true,
+       .data_digest = true,
+       .disable_sqflow = true,
+       .discovery = true,
+       .duplicate_connect = true,
+       .fast_io_fail_tmo = true,
+       .hdr_digest = true,
+       .host_iface = true,
+       .host_traddr = true,
+       .hostid = true,
+       .hostnqn = true,
+       .keep_alive_tmo = true,
+       .nqn = true,
+       .nr_io_queues = true,
+       .nr_poll_queues = true,
+       .nr_write_queues = true,
+       .queue_size = true,
+       .reconnect_delay = true,
+       .tos = true,
+       .traddr = true,
+       .transport = true,
+       .trsvcid = true,
+};
+
 void nvmf_default_config(struct nvme_fabrics_config *cfg)
 {
        memset(cfg, 0, sizeof(*cfg));
@@ -644,6 +675,19 @@ static  int __nvmf_supported_options(nvme_root_t r)
        memset(buf, 0x0, sizeof(buf));
        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
+                        */
+                       nvme_msg(r, LOG_DEBUG,
+                                "Cannot read %s, using default options\n",
+                                nvmf_dev);
+                       *r->options = default_supported_options;
+                       ret = 0;
+                       goto out_close;
+               }
+
                nvme_msg(r, LOG_ERR, "Failed to read from %s: %s\n",
                         nvmf_dev, strerror(errno));
                ret = -ENVME_CONNECT_READ;