Skip to content

Commit

Permalink
iscsi: set netns for tcp and iser hosts
Browse files Browse the repository at this point in the history
This lets iscsi_tcp and ib_iser operate in multiple namespaces.

The logic to store the network namespace during virtual host creation
(due to the way transport-class object setup callbacks function) is in
libiscsi, and shared between iscsi_tcp and ib_iser.

There are a few changes to do so:

* Distinguish between bound and unbound session creation with different
  transport functions, instead of just checking for a NULL endpoint.

This let's the transport code pass the network namespace into the
unbound session creation of iscsi_tcp, without changing the offloading
drivers which all expect an bound endpoint.

iSER has compatibility checks to work without a bound endpoint, so
expose both transport functions there.

* Split endpoint creation into host-bound and with a specified
  namespace, for iSER's use of endpoint objects + virtual
  host-per-session.

This is much like was done with sessions for iscsi_tcp.

Signed-off-by: Chris Leech <cleech@redhat.com>
  • Loading branch information
cleech authored and intel-lab-lkp committed May 6, 2023
1 parent 8c5fa31 commit a287abe
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 39 deletions.
56 changes: 40 additions & 16 deletions drivers/infiniband/ulp/iser/iscsi_iser.c
Expand Up @@ -593,20 +593,10 @@ static inline unsigned int iser_dif_prot_caps(int prot_caps)
return ret;
}

/**
* iscsi_iser_session_create() - create an iscsi-iser session
* @ep: iscsi end-point handle
* @cmds_max: maximum commands in this session
* @qdepth: session command queue depth
* @initial_cmdsn: initiator command sequnce number
*
* Allocates and adds a scsi host, expose DIF supprot if
* exists, and sets up an iscsi session.
*/
static struct iscsi_cls_session *
iscsi_iser_session_create(struct iscsi_endpoint *ep,
__iscsi_iser_session_create(struct iscsi_endpoint *ep,
uint16_t cmds_max, uint16_t qdepth,
uint32_t initial_cmdsn)
uint32_t initial_cmdsn, struct net *net)
{
struct iscsi_cls_session *cls_session;
struct Scsi_Host *shost;
Expand Down Expand Up @@ -656,13 +646,16 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
if (!(ib_dev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG))
shost->virt_boundary_mask = SZ_4K - 1;

iscsi_host_set_netns(shost, ep->netns);

if (iscsi_host_add(shost, ib_dev->dev.parent)) {
mutex_unlock(&iser_conn->state_mutex);
goto free_host;
}
mutex_unlock(&iser_conn->state_mutex);
} else {
shost->can_queue = min_t(u16, cmds_max, ISER_DEF_XMIT_CMDS_MAX);
iscsi_host_set_netns(shost, net);
if (iscsi_host_add(shost, NULL))
goto free_host;
}
Expand Down Expand Up @@ -694,6 +687,34 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
return NULL;
}

/**
* iscsi_iser_session_create() - create an iscsi-iser session
* @ep: iscsi end-point handle
* @cmds_max: maximum commands in this session
* @qdepth: session command queue depth
* @initial_cmdsn: initiator command sequnce number
*
* Allocates and adds a scsi host, expose DIF support if
* exists, and sets up an iscsi session.
*/
static struct iscsi_cls_session *
iscsi_iser_session_create(struct iscsi_endpoint *ep,
uint16_t cmds_max, uint16_t qdepth,
uint32_t initial_cmdsn)
{
return __iscsi_iser_session_create(ep, cmds_max, qdepth,
initial_cmdsn, NULL);
}

static struct iscsi_cls_session *
iscsi_iser_session_create_net(struct net *net,
uint16_t cmds_max, uint16_t qdepth,
uint32_t initial_cmdsn)
{
return __iscsi_iser_session_create(NULL, cmds_max, qdepth,
initial_cmdsn, net);
}

static int iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf, int buflen)
{
Expand Down Expand Up @@ -797,15 +818,15 @@ static int iscsi_iser_get_ep_param(struct iscsi_endpoint *ep,
* Return: iscsi_endpoint created by iscsi layer or ERR_PTR(error)
* if fails.
*/
static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost,
static struct iscsi_endpoint *iscsi_iser_ep_connect(struct net *net,
struct sockaddr *dst_addr,
int non_blocking)
{
int err;
struct iser_conn *iser_conn;
struct iscsi_endpoint *ep;

ep = iscsi_create_endpoint(shost, 0);
ep = iscsi_create_endpoint_net(net, 0);
if (!ep)
return ERR_PTR(-ENOMEM);

Expand Down Expand Up @@ -983,6 +1004,7 @@ static struct iscsi_transport iscsi_iser_transport = {
.caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_TEXT_NEGO,
/* session management */
.create_session = iscsi_iser_session_create,
.create_session_net = iscsi_iser_session_create_net,
.destroy_session = iscsi_iser_session_destroy,
/* connection management */
.create_conn = iscsi_iser_conn_create,
Expand Down Expand Up @@ -1010,9 +1032,11 @@ static struct iscsi_transport iscsi_iser_transport = {
/* recovery */
.session_recovery_timedout = iscsi_session_recovery_timedout,

.ep_connect = iscsi_iser_ep_connect,
.ep_connect_net = iscsi_iser_ep_connect,
.ep_poll = iscsi_iser_ep_poll,
.ep_disconnect = iscsi_iser_ep_disconnect
.ep_disconnect = iscsi_iser_ep_disconnect,
/* net namespace */
.get_netns = iscsi_host_get_netns,
};

static int __init iser_init(void)
Expand Down
15 changes: 7 additions & 8 deletions drivers/scsi/iscsi_tcp.c
Expand Up @@ -922,7 +922,7 @@ iscsi_sw_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
}

static struct iscsi_cls_session *
iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
iscsi_sw_tcp_session_create(struct net *net, uint16_t cmds_max,
uint16_t qdepth, uint32_t initial_cmdsn)
{
struct iscsi_cls_session *cls_session;
Expand All @@ -931,11 +931,6 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
struct Scsi_Host *shost;
int rc;

if (ep) {
printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep);
return NULL;
}

shost = iscsi_host_alloc(&iscsi_sw_tcp_sht,
sizeof(struct iscsi_sw_tcp_host), 1);
if (!shost)
Expand All @@ -952,6 +947,9 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
goto free_host;
shost->can_queue = rc;

tcp_sw_host = iscsi_host_priv(shost);
iscsi_host_set_netns(shost, net);

if (iscsi_host_add(shost, NULL))
goto free_host;

Expand All @@ -968,7 +966,6 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
goto remove_session;

/* We are now fully setup so expose the session to sysfs. */
tcp_sw_host = iscsi_host_priv(shost);
tcp_sw_host->session = session;
return cls_session;

Expand Down Expand Up @@ -1099,7 +1096,7 @@ static struct iscsi_transport iscsi_sw_tcp_transport = {
.caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST
| CAP_DATADGST,
/* session management */
.create_session = iscsi_sw_tcp_session_create,
.create_session_net = iscsi_sw_tcp_session_create,
.destroy_session = iscsi_sw_tcp_session_destroy,
/* connection management */
.create_conn = iscsi_sw_tcp_conn_create,
Expand Down Expand Up @@ -1127,6 +1124,8 @@ static struct iscsi_transport iscsi_sw_tcp_transport = {
.alloc_pdu = iscsi_sw_tcp_pdu_alloc,
/* recovery */
.session_recovery_timedout = iscsi_session_recovery_timedout,
/* net namespace */
.get_netns = iscsi_host_get_netns,
};

static int __init iscsi_sw_tcp_init(void)
Expand Down
16 changes: 16 additions & 0 deletions drivers/scsi/libiscsi.c
Expand Up @@ -3929,6 +3929,22 @@ int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
}
EXPORT_SYMBOL_GPL(iscsi_host_set_param);

void iscsi_host_set_netns(struct Scsi_Host *shost, struct net *netns)
{
struct iscsi_host *ihost = shost_priv(shost);

ihost->net_ns = netns;
}
EXPORT_SYMBOL_GPL(iscsi_host_set_netns);

struct net *iscsi_host_get_netns(struct Scsi_Host *shost)
{
struct iscsi_host *ihost = shost_priv(shost);

return ihost->net_ns;
}
EXPORT_SYMBOL_GPL(iscsi_host_get_netns);

MODULE_AUTHOR("Mike Christie");
MODULE_DESCRIPTION("iSCSI library functions");
MODULE_LICENSE("GPL");
66 changes: 51 additions & 15 deletions drivers/scsi/scsi_transport_iscsi.c
Expand Up @@ -191,6 +191,8 @@ static struct net *iscsi_endpoint_net(struct iscsi_endpoint *ep)
struct Scsi_Host *shost = iscsi_endpoint_to_shost(ep);
struct iscsi_cls_host *ihost;

if (ep->netns)
return ep->netns;
if (!shost)
return &init_net;
ihost = shost->shost_data;
Expand Down Expand Up @@ -229,7 +231,7 @@ static struct attribute_group iscsi_endpoint_group = {
};

struct iscsi_endpoint *
iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
__iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size, struct net *net)
{
struct iscsi_endpoint *ep;
int err, id;
Expand Down Expand Up @@ -257,6 +259,8 @@ iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
ep->dev.class = &iscsi_endpoint_class;
if (shost)
ep->dev.parent = &shost->shost_gendev;
if (net)
ep->netns = net;
dev_set_name(&ep->dev, "ep-%d", id);
err = device_register(&ep->dev);
if (err)
Expand Down Expand Up @@ -284,8 +288,21 @@ iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
kfree(ep);
return NULL;
}

struct iscsi_endpoint *
iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
{
return __iscsi_create_endpoint(shost, dd_size, NULL);
}
EXPORT_SYMBOL_GPL(iscsi_create_endpoint);

struct iscsi_endpoint *
iscsi_create_endpoint_net(struct net *net, int dd_size)
{
return __iscsi_create_endpoint(NULL, dd_size, net);
}
EXPORT_SYMBOL_GPL(iscsi_create_endpoint_net);

void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
{
sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
Expand Down Expand Up @@ -1608,10 +1625,15 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
{
struct Scsi_Host *shost = dev_to_shost(dev);
struct iscsi_cls_host *ihost = shost->shost_data;
struct iscsi_internal *priv = to_iscsi_internal(shost->transportt);
struct iscsi_transport *transport = priv->iscsi_transport;

memset(ihost, 0, sizeof(*ihost));
mutex_init(&ihost->mutex);
ihost->netns = &init_net;
if (transport->get_netns)
ihost->netns = transport->get_netns(shost);
else
ihost->netns = &init_net;

iscsi_bsg_host_add(shost, ihost);
/* ignore any bsg add error - we just can't do sgio */
Expand Down Expand Up @@ -3106,14 +3128,21 @@ static int
iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
struct iscsi_uevent *ev, pid_t pid,
uint32_t initial_cmdsn, uint16_t cmds_max,
uint16_t queue_depth)
uint16_t queue_depth, struct net *net)
{
struct iscsi_transport *transport = priv->iscsi_transport;
struct iscsi_cls_session *session;
struct Scsi_Host *shost;

session = transport->create_session(ep, cmds_max, queue_depth,
initial_cmdsn);
if (ep) {
session = transport->create_session(ep, cmds_max, queue_depth,
initial_cmdsn);
} else {
session = transport->create_session_net(net, cmds_max,
queue_depth,
initial_cmdsn);
}

if (!session)
return -ENOMEM;

Expand Down Expand Up @@ -3231,10 +3260,10 @@ static int iscsi_if_ep_connect(struct net *net,
struct Scsi_Host *shost = NULL;
int non_blocking, err = 0;

if (!transport->ep_connect)
return -EINVAL;

if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
if (!transport->ep_connect)
return -EINVAL;

shost = iscsi_host_lookup(net,
ev->u.ep_connect_through_host.host_no);
if (!shost) {
Expand All @@ -3244,11 +3273,17 @@ static int iscsi_if_ep_connect(struct net *net,
return -ENODEV;
}
non_blocking = ev->u.ep_connect_through_host.non_blocking;
} else
dst_addr = (struct sockaddr *)((char *)ev + sizeof(*ev));
ep = transport->ep_connect(shost, dst_addr, non_blocking);
} else {
if (!transport->ep_connect_net)
return -EINVAL;

non_blocking = ev->u.ep_connect.non_blocking;
dst_addr = (struct sockaddr *)((char *)ev + sizeof(*ev));
ep = transport->ep_connect_net(net, dst_addr, non_blocking);
}

dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
ep = transport->ep_connect(shost, dst_addr, non_blocking);
if (IS_ERR(ep)) {
err = PTR_ERR(ep);
goto release_host;
Expand Down Expand Up @@ -4028,7 +4063,8 @@ static int iscsi_if_transport_conn(struct net *net,
if (!ev->r.retcode)
WRITE_ONCE(conn->state, ISCSI_CONN_BOUND);

if (ev->r.retcode || !transport->ep_connect)
if (ev->r.retcode || (!transport->ep_connect &&
!transport->ep_connect_net))
break;

ep = iscsi_lookup_endpoint(net, ev->u.b_conn.transport_eph);
Expand Down Expand Up @@ -4106,7 +4142,7 @@ iscsi_if_recv_msg(struct net *net, struct sk_buff *skb,
portid,
ev->u.c_session.initial_cmdsn,
ev->u.c_session.cmds_max,
ev->u.c_session.queue_depth);
ev->u.c_session.queue_depth, net);
break;
/* MARK */
case ISCSI_UEVENT_CREATE_BOUND_SESSION:
Expand All @@ -4121,7 +4157,7 @@ iscsi_if_recv_msg(struct net *net, struct sk_buff *skb,
portid,
ev->u.c_bound_session.initial_cmdsn,
ev->u.c_bound_session.cmds_max,
ev->u.c_bound_session.queue_depth);
ev->u.c_bound_session.queue_depth, net);
iscsi_put_endpoint(ep);
break;
case ISCSI_UEVENT_DESTROY_SESSION:
Expand Down Expand Up @@ -4388,7 +4424,7 @@ static ssize_t show_conn_ep_param_##param(struct device *dev, \
*/ \
mutex_lock(&conn->ep_mutex); \
ep = conn->ep; \
if (!ep && t->ep_connect) { \
if (!ep && (t->ep_connect || t->ep_connect_net)) { \
mutex_unlock(&conn->ep_mutex); \
return -ENOTCONN; \
} \
Expand Down
4 changes: 4 additions & 0 deletions include/scsi/libiscsi.h
Expand Up @@ -383,6 +383,7 @@ struct iscsi_host {
int state;

struct workqueue_struct *workq;
struct net *net_ns;
};

/*
Expand Down Expand Up @@ -492,6 +493,9 @@ extern void iscsi_pool_free(struct iscsi_pool *);
extern int iscsi_pool_init(struct iscsi_pool *, int, void ***, int);
extern int iscsi_switch_str_param(char **, char *);

extern void iscsi_host_set_netns(struct Scsi_Host *, struct net *);
extern struct net *iscsi_host_get_netns(struct Scsi_Host *);

/*
* inline functions to deal with padding.
*/
Expand Down

0 comments on commit a287abe

Please sign in to comment.