mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-11 17:43:51 -04:00
nvmet-fcloop: refactor fcloop_nport_alloc and track lport
The checks for a valid input values are mixed with the logic to insert a newly allocated nport. Refactor the function so that first the checks are done. This allows to untangle the setup steps into a more linear form which reduces the complexity of the functions. Also start tracking lport when a lport is assigned to a nport. This ensures, that the lport is not going away as long it is still referenced by a nport. Signed-off-by: Daniel Wagner <wagi@kernel.org> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
committed by
Christoph Hellwig
parent
b999efc8cf
commit
d54a9d7f6d
@@ -1028,6 +1028,9 @@ fcloop_nport_put(struct fcloop_nport *nport)
|
||||
list_del(&nport->nport_list);
|
||||
spin_unlock_irqrestore(&fcloop_lock, flags);
|
||||
|
||||
if (nport->lport)
|
||||
fcloop_lport_put(nport->lport);
|
||||
|
||||
kfree(nport);
|
||||
}
|
||||
|
||||
@@ -1234,6 +1237,25 @@ fcloop_nport_lookup(u64 node_name, u64 port_name)
|
||||
return nport;
|
||||
}
|
||||
|
||||
static struct fcloop_lport *
|
||||
__fcloop_lport_lookup(u64 node_name, u64 port_name)
|
||||
{
|
||||
struct fcloop_lport *lport;
|
||||
|
||||
list_for_each_entry(lport, &fcloop_lports, lport_list) {
|
||||
if (lport->localport->node_name != node_name ||
|
||||
lport->localport->port_name != port_name)
|
||||
continue;
|
||||
|
||||
if (fcloop_lport_get(lport))
|
||||
return lport;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
fcloop_delete_local_port(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@@ -1272,8 +1294,8 @@ fcloop_delete_local_port(struct device *dev, struct device_attribute *attr,
|
||||
static struct fcloop_nport *
|
||||
fcloop_alloc_nport(const char *buf, size_t count, bool remoteport)
|
||||
{
|
||||
struct fcloop_nport *newnport, *nport = NULL;
|
||||
struct fcloop_lport *tmplport, *lport = NULL;
|
||||
struct fcloop_nport *newnport, *nport;
|
||||
struct fcloop_lport *lport;
|
||||
struct fcloop_ctrl_options *opts;
|
||||
unsigned long flags;
|
||||
u32 opts_mask = (remoteport) ? RPORT_OPTS : TGTPORT_OPTS;
|
||||
@@ -1288,10 +1310,8 @@ fcloop_alloc_nport(const char *buf, size_t count, bool remoteport)
|
||||
goto out_free_opts;
|
||||
|
||||
/* everything there ? */
|
||||
if ((opts->mask & opts_mask) != opts_mask) {
|
||||
ret = -EINVAL;
|
||||
if ((opts->mask & opts_mask) != opts_mask)
|
||||
goto out_free_opts;
|
||||
}
|
||||
|
||||
newnport = kzalloc(sizeof(*newnport), GFP_KERNEL);
|
||||
if (!newnport)
|
||||
@@ -1307,60 +1327,61 @@ fcloop_alloc_nport(const char *buf, size_t count, bool remoteport)
|
||||
refcount_set(&newnport->ref, 1);
|
||||
|
||||
spin_lock_irqsave(&fcloop_lock, flags);
|
||||
|
||||
list_for_each_entry(tmplport, &fcloop_lports, lport_list) {
|
||||
if (tmplport->localport->node_name == opts->wwnn &&
|
||||
tmplport->localport->port_name == opts->wwpn)
|
||||
goto out_invalid_opts;
|
||||
|
||||
if (tmplport->localport->node_name == opts->lpwwnn &&
|
||||
tmplport->localport->port_name == opts->lpwwpn)
|
||||
lport = tmplport;
|
||||
lport = __fcloop_lport_lookup(opts->wwnn, opts->wwpn);
|
||||
if (lport) {
|
||||
/* invalid configuration */
|
||||
fcloop_lport_put(lport);
|
||||
goto out_free_newnport;
|
||||
}
|
||||
|
||||
if (remoteport) {
|
||||
if (!lport)
|
||||
goto out_invalid_opts;
|
||||
newnport->lport = lport;
|
||||
}
|
||||
|
||||
list_for_each_entry(nport, &fcloop_nports, nport_list) {
|
||||
if (nport->node_name == opts->wwnn &&
|
||||
nport->port_name == opts->wwpn) {
|
||||
if ((remoteport && nport->rport) ||
|
||||
(!remoteport && nport->tport)) {
|
||||
nport = NULL;
|
||||
goto out_invalid_opts;
|
||||
}
|
||||
|
||||
fcloop_nport_get(nport);
|
||||
|
||||
spin_unlock_irqrestore(&fcloop_lock, flags);
|
||||
|
||||
if (remoteport)
|
||||
nport->lport = lport;
|
||||
if (opts->mask & NVMF_OPT_ROLES)
|
||||
nport->port_role = opts->roles;
|
||||
if (opts->mask & NVMF_OPT_FCADDR)
|
||||
nport->port_id = opts->fcaddr;
|
||||
lport = __fcloop_lport_lookup(opts->lpwwnn, opts->lpwwpn);
|
||||
if (!lport) {
|
||||
/* invalid configuration */
|
||||
goto out_free_newnport;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&newnport->nport_list, &fcloop_nports);
|
||||
nport = __fcloop_nport_lookup(opts->wwnn, opts->wwpn);
|
||||
if (nport) {
|
||||
if ((remoteport && nport->rport) ||
|
||||
(!remoteport && nport->tport)) {
|
||||
/* invalid configuration */
|
||||
goto out_put_nport;
|
||||
}
|
||||
|
||||
/* found existing nport, discard the new nport */
|
||||
kfree(newnport);
|
||||
} else {
|
||||
list_add_tail(&newnport->nport_list, &fcloop_nports);
|
||||
nport = newnport;
|
||||
}
|
||||
|
||||
if (opts->mask & NVMF_OPT_ROLES)
|
||||
nport->port_role = opts->roles;
|
||||
if (opts->mask & NVMF_OPT_FCADDR)
|
||||
nport->port_id = opts->fcaddr;
|
||||
if (lport) {
|
||||
if (!nport->lport)
|
||||
nport->lport = lport;
|
||||
else
|
||||
fcloop_lport_put(lport);
|
||||
}
|
||||
spin_unlock_irqrestore(&fcloop_lock, flags);
|
||||
|
||||
kfree(opts);
|
||||
return newnport;
|
||||
return nport;
|
||||
|
||||
out_invalid_opts:
|
||||
spin_unlock_irqrestore(&fcloop_lock, flags);
|
||||
out_put_nport:
|
||||
if (lport)
|
||||
fcloop_lport_put(lport);
|
||||
fcloop_nport_put(nport);
|
||||
out_free_newnport:
|
||||
spin_unlock_irqrestore(&fcloop_lock, flags);
|
||||
kfree(newnport);
|
||||
out_free_opts:
|
||||
kfree(opts);
|
||||
return nport;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
||||
Reference in New Issue
Block a user