Skip to content

Commit ae8bd60

Browse files
mgurtovoykeithbusch
authored andcommitted
nvme-fabrics: prevent overriding of existing host
When first connecting a target using the "default" host parameters, setting the hostid from the command line during a subsequent connection establishment would override the "default" hostid parameter. This would cause an existing connection that is already using the host definitions to lose its hostid. To address this issue, the code has been modified to allow only 1:1 mapping between hostnqn and hostid. This will maintain unambiguous host identification. Any non 1:1 mapping will be rejected during connection establishment. Tested-by: Noam Gottlieb <[email protected]> Reviewed-by: Israel Rukshin <[email protected]> Signed-off-by: Max Gurtovoy <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent 5e4b55f commit ae8bd60

File tree

1 file changed

+71
-27
lines changed

1 file changed

+71
-27
lines changed

drivers/nvme/host/fabrics.c

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,35 +21,79 @@ static DEFINE_MUTEX(nvmf_hosts_mutex);
2121

2222
static struct nvmf_host *nvmf_default_host;
2323

24-
static struct nvmf_host *__nvmf_host_find(const char *hostnqn)
24+
/**
25+
* __nvmf_host_find() - Find a matching to a previously created host
26+
* @hostnqn: Host NQN to match
27+
* @id: Host ID to match
28+
*
29+
* We have defined a host as how it is perceived by the target.
30+
* Therefore, we don't allow different Host NQNs with the same Host ID.
31+
* Similarly, we do not allow the usage of the same Host NQN with different
32+
* Host IDs. This will maintain unambiguous host identification.
33+
*
34+
* Return: Returns host pointer on success, NULL in case of no match or
35+
* ERR_PTR(-EINVAL) in case of error match.
36+
*/
37+
static struct nvmf_host *__nvmf_host_find(const char *hostnqn, uuid_t *id)
2538
{
2639
struct nvmf_host *host;
2740

41+
lockdep_assert_held(&nvmf_hosts_mutex);
42+
2843
list_for_each_entry(host, &nvmf_hosts, list) {
29-
if (!strcmp(host->nqn, hostnqn))
44+
bool same_hostnqn = !strcmp(host->nqn, hostnqn);
45+
bool same_hostid = uuid_equal(&host->id, id);
46+
47+
if (same_hostnqn && same_hostid)
3048
return host;
49+
50+
if (same_hostnqn) {
51+
pr_err("found same hostnqn %s but different hostid %pUb\n",
52+
hostnqn, id);
53+
return ERR_PTR(-EINVAL);
54+
}
55+
if (same_hostid) {
56+
pr_err("found same hostid %pUb but different hostnqn %s\n",
57+
id, hostnqn);
58+
return ERR_PTR(-EINVAL);
59+
60+
}
3161
}
3262

3363
return NULL;
3464
}
3565

36-
static struct nvmf_host *nvmf_host_add(const char *hostnqn)
66+
static struct nvmf_host *nvmf_host_alloc(const char *hostnqn, uuid_t *id)
67+
{
68+
struct nvmf_host *host;
69+
70+
host = kmalloc(sizeof(*host), GFP_KERNEL);
71+
if (!host)
72+
return NULL;
73+
74+
kref_init(&host->ref);
75+
uuid_copy(&host->id, id);
76+
strscpy(host->nqn, hostnqn, NVMF_NQN_SIZE);
77+
78+
return host;
79+
}
80+
81+
static struct nvmf_host *nvmf_host_add(const char *hostnqn, uuid_t *id)
3782
{
3883
struct nvmf_host *host;
3984

4085
mutex_lock(&nvmf_hosts_mutex);
41-
host = __nvmf_host_find(hostnqn);
42-
if (host) {
86+
host = __nvmf_host_find(hostnqn, id);
87+
if (IS_ERR(host)) {
88+
goto out_unlock;
89+
} else if (host) {
4390
kref_get(&host->ref);
4491
goto out_unlock;
4592
}
4693

47-
host = kmalloc(sizeof(*host), GFP_KERNEL);
94+
host = nvmf_host_alloc(hostnqn, id);
4895
if (!host)
49-
goto out_unlock;
50-
51-
kref_init(&host->ref);
52-
strscpy(host->nqn, hostnqn, NVMF_NQN_SIZE);
96+
return ERR_PTR(-ENOMEM);
5397

5498
list_add_tail(&host->list, &nvmf_hosts);
5599
out_unlock:
@@ -60,16 +104,17 @@ static struct nvmf_host *nvmf_host_add(const char *hostnqn)
60104
static struct nvmf_host *nvmf_host_default(void)
61105
{
62106
struct nvmf_host *host;
107+
char nqn[NVMF_NQN_SIZE];
108+
uuid_t id;
63109

64-
host = kmalloc(sizeof(*host), GFP_KERNEL);
110+
uuid_gen(&id);
111+
snprintf(nqn, NVMF_NQN_SIZE,
112+
"nqn.2014-08.org.nvmexpress:uuid:%pUb", &id);
113+
114+
host = nvmf_host_alloc(nqn, &id);
65115
if (!host)
66116
return NULL;
67117

68-
kref_init(&host->ref);
69-
uuid_gen(&host->id);
70-
snprintf(host->nqn, NVMF_NQN_SIZE,
71-
"nqn.2014-08.org.nvmexpress:uuid:%pUb", &host->id);
72-
73118
mutex_lock(&nvmf_hosts_mutex);
74119
list_add_tail(&host->list, &nvmf_hosts);
75120
mutex_unlock(&nvmf_hosts_mutex);
@@ -633,6 +678,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
633678
size_t nqnlen = 0;
634679
int ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO;
635680
uuid_t hostid;
681+
char hostnqn[NVMF_NQN_SIZE];
636682

637683
/* Set defaults */
638684
opts->queue_size = NVMF_DEF_QUEUE_SIZE;
@@ -649,7 +695,9 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
649695
if (!options)
650696
return -ENOMEM;
651697

652-
uuid_gen(&hostid);
698+
/* use default host if not given by user space */
699+
uuid_copy(&hostid, &nvmf_default_host->id);
700+
strscpy(hostnqn, nvmf_default_host->nqn, NVMF_NQN_SIZE);
653701

654702
while ((p = strsep(&o, ",\n")) != NULL) {
655703
if (!*p)
@@ -795,12 +843,8 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
795843
ret = -EINVAL;
796844
goto out;
797845
}
798-
opts->host = nvmf_host_add(p);
846+
strscpy(hostnqn, p, NVMF_NQN_SIZE);
799847
kfree(p);
800-
if (!opts->host) {
801-
ret = -ENOMEM;
802-
goto out;
803-
}
804848
break;
805849
case NVMF_OPT_RECONNECT_DELAY:
806850
if (match_int(args, &token)) {
@@ -957,13 +1001,13 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
9571001
opts->fast_io_fail_tmo, ctrl_loss_tmo);
9581002
}
9591003

960-
if (!opts->host) {
961-
kref_get(&nvmf_default_host->ref);
962-
opts->host = nvmf_default_host;
1004+
opts->host = nvmf_host_add(hostnqn, &hostid);
1005+
if (IS_ERR(opts->host)) {
1006+
ret = PTR_ERR(opts->host);
1007+
opts->host = NULL;
1008+
goto out;
9631009
}
9641010

965-
uuid_copy(&opts->host->id, &hostid);
966-
9671011
out:
9681012
kfree(options);
9691013
return ret;

0 commit comments

Comments
 (0)