[PATCH nvme-7.3 3/4] nvme-fabrics: add helpers for subsystem and host identity options
From: raoxu
Date: Fri Aug 21 2026 - 02:28:02 EST
From: Xu Rao <raoxu@xxxxxxxxxxxxx>
The nqn, hostnqn and hostid options also start with match_strdup(), but
unlike the direct string replacements handled by nvmf_parse_string_option()
they perform option-specific validation or conversion before parsing is
complete.
Move each lifetime into a helper whose name identifies the value being
parsed:
nvmf_parse_subsysnqn() handles NVMF_OPT_NQN. It replaces
opts->subsysnqn, checks NVMF_NQN_SIZE and updates discovery_nqn. Using
subsysnqn in the helper name distinguishes the subsystem NQN from the
host NQN at the call site.
nvmf_parse_hostnqn() handles the hostnqn option. It keeps the existing
host-assignment check, validates the temporary NQN, copies it to the
hostnqn buffer and frees the temporary allocation before returning.
nvmf_parse_hostid() handles the hostid option. It converts the temporary
string to uuid_t and frees the duplicated string on both success and
failure paths.
These three helpers are grouped because they parse non-sensitive identity
values that require validation or conversion rather than a simple owned
string replacement. Preserve the existing validation and ownership
ordering while moving the code.
No functional change is intended.
Suggested-by: Christoph Hellwig <hch@xxxxxx>
Signed-off-by: Xu Rao <raoxu@xxxxxxxxxxxxx>
---
drivers/nvme/host/fabrics.c | 118 +++++++++++++++++++++---------------
1 file changed, 69 insertions(+), 49 deletions(-)
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index aab3fd279d0e..120e57964cdd 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -725,13 +725,75 @@ static int nvmf_parse_string_option(substring_t *args, char **dst)
return 0;
}
+static int nvmf_parse_subsysnqn(struct nvmf_ctrl_options *opts, substring_t *args)
+{
+ char *nqn;
+
+ nqn = match_strdup(args);
+ if (!nqn)
+ return -ENOMEM;
+
+ kfree(opts->subsysnqn);
+ opts->subsysnqn = nqn;
+ if (strlen(opts->subsysnqn) >= NVMF_NQN_SIZE) {
+ pr_err("%s needs to be < %d bytes\n",
+ opts->subsysnqn, NVMF_NQN_SIZE);
+ return -EINVAL;
+ }
+
+ opts->discovery_nqn = !strcmp(opts->subsysnqn, NVME_DISC_SUBSYS_NAME);
+ return 0;
+}
+
+static int nvmf_parse_hostnqn(struct nvmf_ctrl_options *opts,
+ substring_t *args, char *hostnqn)
+{
+ char *nqn;
+
+ if (opts->host) {
+ pr_err("hostnqn already user-assigned: %s\n", opts->host->nqn);
+ return -EADDRINUSE;
+ }
+
+ nqn = match_strdup(args);
+ if (!nqn)
+ return -ENOMEM;
+
+ if (strlen(nqn) >= NVMF_NQN_SIZE) {
+ pr_err("%s needs to be < %d bytes\n", nqn, NVMF_NQN_SIZE);
+ kfree(nqn);
+ return -EINVAL;
+ }
+
+ strscpy(hostnqn, nqn, NVMF_NQN_SIZE);
+ kfree(nqn);
+ return 0;
+}
+
+static int nvmf_parse_hostid(substring_t *args, uuid_t *hostid)
+{
+ char *id;
+ int ret;
+
+ id = match_strdup(args);
+ if (!id)
+ return -ENOMEM;
+
+ ret = uuid_parse(id, hostid);
+ if (ret) {
+ pr_err("Invalid hostid %s\n", id);
+ ret = -EINVAL;
+ }
+ kfree(id);
+ return ret;
+}
+
static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
const char *buf)
{
substring_t args[MAX_OPT_ARGS];
char *options, *o, *option, *p;
int token, ret = 0;
- size_t nqnlen = 0;
int ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO, key_id;
uuid_t hostid;
char hostnqn[NVMF_NQN_SIZE];
@@ -773,23 +835,9 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
goto out;
break;
case NVMF_OPT_NQN:
- p = match_strdup(args);
- if (!p) {
- ret = -ENOMEM;
- goto out;
- }
- kfree(opts->subsysnqn);
- opts->subsysnqn = p;
- nqnlen = strlen(opts->subsysnqn);
- if (nqnlen >= NVMF_NQN_SIZE) {
- pr_err("%s needs to be < %d bytes\n",
- opts->subsysnqn, NVMF_NQN_SIZE);
- ret = -EINVAL;
+ ret = nvmf_parse_subsysnqn(opts, args);
+ if (ret)
goto out;
- }
- opts->discovery_nqn =
- !(strcmp(opts->subsysnqn,
- NVME_DISC_SUBSYS_NAME));
break;
case NVMF_OPT_TRADDR:
ret = nvmf_parse_string_option(args, &opts->traddr);
@@ -873,27 +921,9 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
opts->fast_io_fail_tmo = token;
break;
case NVMF_OPT_HOSTNQN:
- if (opts->host) {
- pr_err("hostnqn already user-assigned: %s\n",
- opts->host->nqn);
- ret = -EADDRINUSE;
- goto out;
- }
- p = match_strdup(args);
- if (!p) {
- ret = -ENOMEM;
- goto out;
- }
- nqnlen = strlen(p);
- if (nqnlen >= NVMF_NQN_SIZE) {
- pr_err("%s needs to be < %d bytes\n",
- p, NVMF_NQN_SIZE);
- kfree(p);
- ret = -EINVAL;
+ ret = nvmf_parse_hostnqn(opts, args, hostnqn);
+ if (ret)
goto out;
- }
- strscpy(hostnqn, p, NVMF_NQN_SIZE);
- kfree(p);
break;
case NVMF_OPT_RECONNECT_DELAY:
if (match_int(args, &token)) {
@@ -918,19 +948,9 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
goto out;
break;
case NVMF_OPT_HOST_ID:
- p = match_strdup(args);
- if (!p) {
- ret = -ENOMEM;
- goto out;
- }
- ret = uuid_parse(p, &hostid);
- if (ret) {
- pr_err("Invalid hostid %s\n", p);
- ret = -EINVAL;
- kfree(p);
+ ret = nvmf_parse_hostid(args, &hostid);
+ if (ret)
goto out;
- }
- kfree(p);
break;
case NVMF_OPT_DUP_CONNECT:
opts->duplicate_connect = true;
--
2.50.1