Skip to contentSkip to conversation

Make iscsid-kernel communications namespace-aware

RFC In review Lee Duncan 4 participants 39 messages Feb 8, 2023 – Apr 21, 2023

Subsystems (10)
lore
Share & tools
lore

Lee Duncan

author
#0 lore raw

cover Make iscsid-kernel communications namespace-aware

From: Lee Duncan <[email protected]>

This is a request for comment on a set of patches that modify the kernel iSCSI initiator communications so that they are namespace-aware. The goal is to allow multiple iSCSI daemon (iscsid) to run at once as long as they are in separate namespaces, and so that iscsid can run in containers.

Comments and suggestions are more than welcome. I do not expect that this code is production-ready yet, and networking isn't my strongest suit (yet).

These patches were originally posted in 2015 by Chris Leech. There were some issues at the time about how to handle namespaces going away. I hope to address any issues raised with this patchset and then to merge these changes upstream to address working in working in containers.

My contribution thus far has been to update these patches to work with the current upstream kernel.

Chris Leech/Lee Duncan (9):
iscsi: create per-net iscsi netlink kernel sockets
iscsi: associate endpoints with a host
iscsi: sysfs filtering by network namespace
iscsi: make all iSCSI netlink multicast namespace aware
iscsi: set netns for iscsi_tcp hosts
iscsi: check net namespace for all iscsi lookup
iscsi: convert flashnode devices from bus to class
iscsi: rename iscsi_bus_flash_* to iscsi_flash_*
iscsi: filter flashnode sysfs by net namespace

 drivers/infiniband/ulp/iser/iscsi_iser.c |   7 +-
 drivers/scsi/be2iscsi/be_iscsi.c         |   6 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c         |   6 +-
 drivers/scsi/cxgbi/libcxgbi.c            |   6 +-
 drivers/scsi/iscsi_tcp.c                 |   7 +
 drivers/scsi/qedi/qedi_iscsi.c           |   6 +-
 drivers/scsi/qla4xxx/ql4_os.c            |  64 +--
 drivers/scsi/scsi_transport_iscsi.c      | 625 ++++++++++++++++-------
 include/scsi/scsi_transport_iscsi.h      |  63 ++-
 9 files changed, 537 insertions(+), 253 deletions(-)
Signature · 1 line
2.39.1
author
#1 lore raw

RFC PATCH 1/9 iscsi: create per-net iscsi netlink kernel sockets

From: Lee Duncan <[email protected]>

Prepare iSCSI netlink to operate in multiple namespaces.

---
 drivers/scsi/scsi_transport_iscsi.c | 73 +++++++++++++++++++++++++----
 1 file changed, 63 insertions(+), 10 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +63 -10
index b9b97300e3b3..be69cea9c6f8 100644
@@ -13,6 +13,8 @@
 #include <linux/bsg-lib.h>
 #include <linux/idr.h>
 #include <net/tcp.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
@@ -1597,7 +1599,11 @@ static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
 			       NULL,
 			       NULL);
 
-static struct sock *nls;
+struct iscsi_net {
+	struct sock *nls;
+};
+
+static int iscsi_net_id __read_mostly;
 static DEFINE_MUTEX(rx_queue_mutex);
 
 static LIST_HEAD(sesslist);
@@ -2552,14 +2558,32 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt)
 }
 
 static int
-iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
+iscsi_multicast_netns(struct net *net, struct sk_buff *skb,
+		      uint32_t group, gfp_t gfp)
 {
+	struct sock *nls;
+	struct iscsi_net *isn;
+
+	isn = net_generic(net, iscsi_net_id);
+	nls = isn->nls;
 	return nlmsg_multicast(nls, skb, 0, group, gfp);
 }
 
+static int
+iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
+{
+	return iscsi_multicast_netns(&init_net, skb, group, gfp);
+}
+
 static int
 iscsi_unicast_skb(struct sk_buff *skb, u32 portid)
 {
+	struct sock *nls;
+	struct iscsi_net *isn;
+	struct net *net = &init_net;
+
+	isn = net_generic(net, iscsi_net_id);
+	nls = isn->nls;
 	return nlmsg_unicast(nls, skb, portid);
 }
 
@@ -4937,13 +4961,42 @@ void iscsi_dbg_trace(void (*trace)(struct device *dev, struct va_format *),
 }
 EXPORT_SYMBOL_GPL(iscsi_dbg_trace);
 
-static __init int iscsi_transport_init(void)
+static int __net_init iscsi_net_init(struct net *net)
 {
-	int err;
+	struct sock *nls;
+	struct iscsi_net *isn;
 	struct netlink_kernel_cfg cfg = {
 		.groups	= 1,
 		.input	= iscsi_if_rx,
 	};
+
+	nls = netlink_kernel_create(net, NETLINK_ISCSI, &cfg);
+	if (!nls)
+		return -ENOMEM;
+	isn = net_generic(net, iscsi_net_id);
+	isn->nls = nls;
+	return 0;
+}
+
+static void __net_exit iscsi_net_exit(struct net *net)
+{
+	struct iscsi_net *isn;
+
+	isn = net_generic(net, iscsi_net_id);
+	netlink_kernel_release(isn->nls);
+	isn->nls = NULL;
+}
+
+static struct pernet_operations iscsi_net_ops = {
+	.init = iscsi_net_init,
+	.exit = iscsi_net_exit,
+	.id   = &iscsi_net_id,
+	.size = sizeof(struct iscsi_net),
+};
+
+static __init int iscsi_transport_init(void)
+{
+	int err;
 	printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
 		ISCSI_TRANSPORT_VERSION);
 
@@ -4977,8 +5030,8 @@ static __init int iscsi_transport_init(void)
 	if (err)
 		goto unregister_session_class;
 
-	nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, &cfg);
-	if (!nls) {
+	err = register_pernet_subsys(&iscsi_net_ops);
+	if (err) {
 		err = -ENOBUFS;
 		goto unregister_flashnode_bus;
 	}
@@ -4988,13 +5041,13 @@ static __init int iscsi_transport_init(void)
 			"iscsi_conn_cleanup");
 	if (!iscsi_conn_cleanup_workq) {
 		err = -ENOMEM;
-		goto release_nls;
+		goto unregister_pernet_subsys;
 	}
 
 	return 0;
 
-release_nls:
-	netlink_kernel_release(nls);
+unregister_pernet_subsys:
+	unregister_pernet_subsys(&iscsi_net_ops);
 unregister_flashnode_bus:
 	bus_unregister(&iscsi_flashnode_bus);
 unregister_session_class:
@@ -5015,7 +5068,7 @@ static __init int iscsi_transport_init(void)
 static void __exit iscsi_transport_exit(void)
 {
 	destroy_workqueue(iscsi_conn_cleanup_workq);
-	netlink_kernel_release(nls);
+	unregister_pernet_subsys(&iscsi_net_ops);
 	bus_unregister(&iscsi_flashnode_bus);
 	transport_class_unregister(&iscsi_connection_class);
 	transport_class_unregister(&iscsi_session_class);
Signature · 1 line
2.39.1
Reviewed-by on v1 1/9
#2 lore raw

Re: [RFC PATCH 1/9] iscsi: create per-net iscsi netlink kernel sockets

Quoted 10 lines · Lee Duncan

From: Lee Duncan <[email protected]>

Prepare iSCSI netlink to operate in multiple namespaces.

---
  drivers/scsi/scsi_transport_iscsi.c | 73 +++++++++++++++++++++++++----
  1 file changed, 63 insertions(+), 10 deletions(-)

Cheers,

Hannes

author
#3 lore raw

RFC PATCH 2/9 iscsi: associate endpoints with a host

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

Right now the iscsi_endpoint is only linked to a connection once that connection has been established. For net namespace filtering of the sysfs objects, associate an endpoint with the host that it was allocated for when it is created.

---
 drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +-
 drivers/scsi/be2iscsi/be_iscsi.c         | 2 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c         | 2 +-
 drivers/scsi/cxgbi/libcxgbi.c            | 2 +-
 drivers/scsi/qedi/qedi_iscsi.c           | 2 +-
 drivers/scsi/qla4xxx/ql4_os.c            | 2 +-
 drivers/scsi/scsi_transport_iscsi.c      | 3 ++-
 include/scsi/scsi_transport_iscsi.h      | 6 +++++-
 8 files changed, 13 insertions(+), 8 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +1 -1
index 620ae5b2d80d..d38c909b462f 100644
@@ -802,7 +802,7 @@ static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost,
 	struct iser_conn *iser_conn;
 	struct iscsi_endpoint *ep;
 
-	ep = iscsi_create_endpoint(0);
+	ep = iscsi_create_endpoint(shost, 0);
 	if (!ep)
 		return ERR_PTR(-ENOMEM);
 
drivers/scsi/be2iscsi/be_iscsi.c +1 -1
index 8aeaddc93b16..c893d193f5ef 100644
@@ -1168,7 +1168,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
 		return ERR_PTR(ret);
 	}
 
-	ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct beiscsi_endpoint));
 	if (!ep) {
 		ret = -ENOMEM;
 		return ERR_PTR(ret);
drivers/scsi/bnx2i/bnx2i_iscsi.c +1 -1
index a3c800e04a2e..ac63e93e07c6 100644
@@ -384,7 +384,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
 	struct bnx2i_endpoint *bnx2i_ep;
 	u32 ec_div;
 
-	ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
+	ep = iscsi_create_endpoint(hba->shost, sizeof(*bnx2i_ep));
 	if (!ep) {
 		printk(KERN_ERR "bnx2i: Could not allocate ep\n");
 		return NULL;
drivers/scsi/cxgbi/libcxgbi.c +1 -1
index af281e271f88..94edf8e1fb0c 100644
@@ -2926,7 +2926,7 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost,
 		goto release_conn;
 	}
 
-	ep = iscsi_create_endpoint(sizeof(*cep));
+	ep = iscsi_create_endpoint(shost, sizeof(*cep));
 	if (!ep) {
 		err = -ENOMEM;
 		pr_info("iscsi alloc ep, OOM.\n");
drivers/scsi/qedi/qedi_iscsi.c +1 -1
index 31ec429104e2..4baf1dbb8e92 100644
@@ -931,7 +931,7 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
 		return ERR_PTR(-ENXIO);
 	}
 
-	ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct qedi_endpoint));
 	if (!ep) {
 		QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n");
 		ret = -ENOMEM;
drivers/scsi/qla4xxx/ql4_os.c +1 -1
index 005502125b27..acebf9c92c04 100644
@@ -1717,7 +1717,7 @@ qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
 	}
 
 	ha = iscsi_host_priv(shost);
-	ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct qla_endpoint));
 	if (!ep) {
 		ret = -ENOMEM;
 		return ERR_PTR(ret);
drivers/scsi/scsi_transport_iscsi.c +2 -1
index be69cea9c6f8..86bafdb862a5 100644
@@ -204,7 +204,7 @@ static struct attribute_group iscsi_endpoint_group = {
 };
 
 struct iscsi_endpoint *
-iscsi_create_endpoint(int dd_size)
+iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
 {
 	struct iscsi_endpoint *ep;
 	int err, id;
@@ -230,6 +230,7 @@ iscsi_create_endpoint(int dd_size)
 
 	ep->id = id;
 	ep->dev.class = &iscsi_endpoint_class;
+	ep->dev.parent = &shost->shost_gendev;
 	dev_set_name(&ep->dev, "ep-%d", id);
 	err = device_register(&ep->dev);
         if (err)
include/scsi/scsi_transport_iscsi.h +5 -1
index 34c03707fb6e..268ccaac1c05 100644
@@ -287,6 +287,9 @@ struct iscsi_cls_session {
 #define iscsi_session_to_shost(_session) \
 	dev_to_shost(_session->dev.parent)
 
+#define iscsi_endpoint_to_shost(_ep) \
+	dev_to_shost(_ep->dev.parent)
+
 #define starget_to_session(_stgt) \
 	iscsi_dev_to_session(_stgt->dev.parent)
 
@@ -462,7 +465,8 @@ extern void iscsi_put_conn(struct iscsi_cls_conn *conn);
 extern void iscsi_get_conn(struct iscsi_cls_conn *conn);
 extern void iscsi_unblock_session(struct iscsi_cls_session *session);
 extern void iscsi_block_session(struct iscsi_cls_session *session);
-extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
+extern struct iscsi_endpoint *iscsi_create_endpoint(struct Scsi_Host *shost,
+						    int dd_size);
 extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
 extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
 extern void iscsi_put_endpoint(struct iscsi_endpoint *ep);
Signature · 1 line
2.39.1
#4 lore raw

Re: [RFC PATCH 2/9] iscsi: associate endpoints with a host

Quoted 112 lines · Lee Duncan

From: Lee Duncan <[email protected]>

Right now the iscsi_endpoint is only linked to a connection once that connection has been established. For net namespace filtering of the sysfs objects, associate an endpoint with the host that it was allocated for when it is created.

---
  drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +-
  drivers/scsi/be2iscsi/be_iscsi.c         | 2 +-
  drivers/scsi/bnx2i/bnx2i_iscsi.c         | 2 +-
  drivers/scsi/cxgbi/libcxgbi.c            | 2 +-
  drivers/scsi/qedi/qedi_iscsi.c           | 2 +-
  drivers/scsi/qla4xxx/ql4_os.c            | 2 +-
  drivers/scsi/scsi_transport_iscsi.c      | 3 ++-
  include/scsi/scsi_transport_iscsi.h      | 6 +++++-
  8 files changed, 13 insertions(+), 8 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +1 -1
index 620ae5b2d80d..d38c909b462f 100644
@@ -802,7 +802,7 @@ static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost,
  	struct iser_conn *iser_conn;
  	struct iscsi_endpoint *ep;
 
-	ep = iscsi_create_endpoint(0);
+	ep = iscsi_create_endpoint(shost, 0);
  	if (!ep)
  		return ERR_PTR(-ENOMEM);
 
drivers/scsi/be2iscsi/be_iscsi.c +1 -1
index 8aeaddc93b16..c893d193f5ef 100644
@@ -1168,7 +1168,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
  		return ERR_PTR(ret);
  	}
 
-	ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct beiscsi_endpoint));
  	if (!ep) {
  		ret = -ENOMEM;
  		return ERR_PTR(ret);
drivers/scsi/bnx2i/bnx2i_iscsi.c +1 -1
index a3c800e04a2e..ac63e93e07c6 100644
@@ -384,7 +384,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
  	struct bnx2i_endpoint *bnx2i_ep;
  	u32 ec_div;
 
-	ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
+	ep = iscsi_create_endpoint(hba->shost, sizeof(*bnx2i_ep));
  	if (!ep) {
  		printk(KERN_ERR "bnx2i: Could not allocate ep\n");
  		return NULL;
drivers/scsi/cxgbi/libcxgbi.c +1 -1
index af281e271f88..94edf8e1fb0c 100644
@@ -2926,7 +2926,7 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost,
  		goto release_conn;
  	}
 
-	ep = iscsi_create_endpoint(sizeof(*cep));
+	ep = iscsi_create_endpoint(shost, sizeof(*cep));
  	if (!ep) {
  		err = -ENOMEM;
  		pr_info("iscsi alloc ep, OOM.\n");
drivers/scsi/qedi/qedi_iscsi.c +1 -1
index 31ec429104e2..4baf1dbb8e92 100644
@@ -931,7 +931,7 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
  		return ERR_PTR(-ENXIO);
  	}
 
-	ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct qedi_endpoint));
  	if (!ep) {
  		QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n");
  		ret = -ENOMEM;
drivers/scsi/qla4xxx/ql4_os.c +1 -1
index 005502125b27..acebf9c92c04 100644
@@ -1717,7 +1717,7 @@ qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
  	}
 
  	ha = iscsi_host_priv(shost);
-	ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct qla_endpoint));
  	if (!ep) {
  		ret = -ENOMEM;
  		return ERR_PTR(ret);
drivers/scsi/scsi_transport_iscsi.c +1 -1
index be69cea9c6f8..86bafdb862a5 100644
@@ -204,7 +204,7 @@ static struct attribute_group iscsi_endpoint_group = {
  };
 
  struct iscsi_endpoint *
-iscsi_create_endpoint(int dd_size)
+iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
  {
  	struct iscsi_endpoint *ep;
  	int err, id;

drivers/scsi/scsi_transport_iscsi.c iscsi_create_endpoint(int dd_size) · line 236

Quoted 7 lines
drivers/scsi/scsi_transport_iscsi.c +1 -0
@@ -230,6 +230,7 @@ iscsi_create_endpoint(int dd_size)
 
  	ep->id = id;
  	ep->dev.class = &iscsi_endpoint_class;
+	ep->dev.parent = &shost->shost_gendev;
  	dev_set_name(&ep->dev, "ep-%d", id);
  	err = device_register(&ep->dev);
          if (err)

Umm... doesn't this change the sysfs layout?
IE won't the endpoint node be moved under the Scsi_Host directory?

But even if it does: do we care?

Cheers,

Hannes

author
#5 lore raw

Re: [RFC PATCH 2/9] iscsi: associate endpoints with a host

Quoted 113 lines · Hannes Reinecke
Quoted 101 lines · Lee Duncan

From: Lee Duncan <[email protected]>
Right now the iscsi_endpoint is only linked to a connection once that connection has been established. For net namespace filtering of the sysfs objects, associate an endpoint with the host that it was allocated for when it is created.

---
 drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +-
 drivers/scsi/be2iscsi/be_iscsi.c         | 2 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c         | 2 +-
 drivers/scsi/cxgbi/libcxgbi.c            | 2 +-
 drivers/scsi/qedi/qedi_iscsi.c           | 2 +-
 drivers/scsi/qla4xxx/ql4_os.c            | 2 +-
 drivers/scsi/scsi_transport_iscsi.c      | 3 ++-
 include/scsi/scsi_transport_iscsi.h      | 6 +++++-
 8 files changed, 13 insertions(+), 8 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +1 -0
index 620ae5b2d80d..d38c909b462f 100644
@@ -802,7 +802,7 @@ static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost,
 	struct iser_conn *iser_conn;
 	struct iscsi_endpoint *ep;
 -	ep = iscsi_create_endpoint(0);
+	ep = iscsi_create_endpoint(shost, 0);
 	if (!ep)
 		return ERR_PTR(-ENOMEM);
 diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c

index 8aeaddc93b16..c893d193f5ef 100644

drivers/scsi/be2iscsi/be_iscsi.c +1 -0
@@ -1168,7 +1168,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
 		return ERR_PTR(ret);
 	}
 -	ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct beiscsi_endpoint));
 	if (!ep) {
 		ret = -ENOMEM;
 		return ERR_PTR(ret);
drivers/scsi/bnx2i/bnx2i_iscsi.c +1 -0
index a3c800e04a2e..ac63e93e07c6 100644
@@ -384,7 +384,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
 	struct bnx2i_endpoint *bnx2i_ep;
 	u32 ec_div;
 -	ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
+	ep = iscsi_create_endpoint(hba->shost, sizeof(*bnx2i_ep));
 	if (!ep) {
 		printk(KERN_ERR "bnx2i: Could not allocate ep\n");
 		return NULL;
drivers/scsi/cxgbi/libcxgbi.c +1 -0
index af281e271f88..94edf8e1fb0c 100644
@@ -2926,7 +2926,7 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost,
 		goto release_conn;
 	}
 -	ep = iscsi_create_endpoint(sizeof(*cep));
+	ep = iscsi_create_endpoint(shost, sizeof(*cep));
 	if (!ep) {
 		err = -ENOMEM;
 		pr_info("iscsi alloc ep, OOM.\n");
drivers/scsi/qedi/qedi_iscsi.c +1 -0
index 31ec429104e2..4baf1dbb8e92 100644
@@ -931,7 +931,7 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
 		return ERR_PTR(-ENXIO);
 	}
 -	ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct qedi_endpoint));
 	if (!ep) {
 		QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n");
 		ret = -ENOMEM;
drivers/scsi/qla4xxx/ql4_os.c +1 -1
index 005502125b27..acebf9c92c04 100644
@@ -1717,7 +1717,7 @@ qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
 	}
   	ha = iscsi_host_priv(shost);
-	ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
+	ep = iscsi_create_endpoint(shost, sizeof(struct qla_endpoint));
 	if (!ep) {
 		ret = -ENOMEM;
 		return ERR_PTR(ret);
drivers/scsi/scsi_transport_iscsi.c +1 -1
index be69cea9c6f8..86bafdb862a5 100644
@@ -204,7 +204,7 @@ static struct attribute_group iscsi_endpoint_group = {
 };
   struct iscsi_endpoint *
-iscsi_create_endpoint(int dd_size)
+iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
 {
 	struct iscsi_endpoint *ep;
 	int err, id;

drivers/scsi/scsi_transport_iscsi.c iscsi_create_endpoint(int dd_size) · line 235

Quoted 6 lines
drivers/scsi/scsi_transport_iscsi.c +1 -0
@@ -230,6 +230,7 @@ iscsi_create_endpoint(int dd_size)
   	ep->id = id;
 	ep->dev.class = &iscsi_endpoint_class;
+	ep->dev.parent = &shost->shost_gendev;
 	dev_set_name(&ep->dev, "ep-%d", id);
 	err = device_register(&ep->dev);
         if (err)

Umm... doesn't this change the sysfs layout?
IE won't the endpoint node be moved under the Scsi_Host directory?

Quoted 7 lines

But even if it does: do we care?

Cheers,

Hannes

No, it’s still /sys/class/iscsi_endpoint, since the dev.class hasn’t changed.

—
Lee

maintainer
#6 lore raw

Re: [RFC PATCH 2/9] iscsi: associate endpoints with a host

In reply to Hannes Reinecke
Quoted 13 lines · Hannes Reinecke

drivers/scsi/scsi_transport_iscsi.c iscsi_create_endpoint(int dd_size) · line 235

Quoted 8 lines · Lee Duncan

From: Lee Duncan <[email protected]>

drivers/scsi/scsi_transport_iscsi.c +1 -0
@@ -230,6 +230,7 @@ iscsi_create_endpoint(int dd_size)
  	ep->id = id;
  	ep->dev.class = &iscsi_endpoint_class;
+	ep->dev.parent = &shost->shost_gendev;
  	dev_set_name(&ep->dev, "ep-%d", id);
  	err = device_register(&ep->dev);
          if (err)

Umm... doesn't this change the sysfs layout?
IE won't the endpoint node be moved under the Scsi_Host directory?

Quoted 1 line

But even if it does: do we care?

It does, but it shouldn't matter. The Open-iSCSI tools look under the subsystem, not the device path. Being a child of the host makes more sense then being a floating virtual device.

I just re-tested with bnx2i to make sure moving an endpoint devpath in sysfs didn't break anything.

- Chris

maintainer
#7 lore raw

Re: [RFC PATCH 2/9] iscsi: associate endpoints with a host

In reply to Lee Duncan
Quoted 14 lines · Lee Duncan

Right now the iscsi_endpoint is only linked to a connection once that connection has been established. For net namespace filtering of the sysfs objects, associate an endpoint with the host that it was allocated for when it is created.

---

drivers/infiniband/ulp/iser/iscsi_iser.c +0 -0
index 6b7603765383..212fa7aa9810 100644

drivers/infiniband/ulp/iser/iscsi_iser.c static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost, · line 807

Quoted 7 lines
drivers/infiniband/ulp/iser/iscsi_iser.c +1 -1
@@ -802,7 +802,7 @@ static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost,
 	struct iser_conn *iser_conn;
 	struct iscsi_endpoint *ep;
 
-	ep = iscsi_create_endpoint(0);
+	ep = iscsi_create_endpoint(shost, 0);
 	if (!ep)
 		return ERR_PTR(-ENOMEM);

I started trying[1] to look at iSER, and I think this is a problem. iSER is the only iSCSI driver that uses endpoint objects, but does not require then to be bound to a host. That means that iscsi_iser_ep_connect can be called with a null shost.

So this fails, and not in a new namespace.
It just breaks iSER entirely.

I think we need to preserve support for the iscsi_endpoint device having a virtual device path for iSER.

Also, enabling net namespace support for iSER might require the ability to create an endpoint directly in a namespace instead of on a host. Kind of like the create_session discussion for iscsi_tcp.

- Chris

[1] I say trying, becuase before going and borrowing an RDMA setup I thought I'd give the kernel target and either siw or rxe a try. The isert module seems to have issues with siw, and I think maybe any iWARP, where setting enable_iser on a port will try and re-use the TCP port number and fail due to it being in use. With rxe my host failed, but that's becuase of this create_endpoint issue.

maintainer
#8 lore raw

Re: [RFC PATCH 2/9] iscsi: associate endpoints with a host

I managed to fix the iSER endpoint issue by making endpoints created without a host valid again. Once I had iSER working, I went ahead and made it network namespace aware as well.

Only tested with software roce (rxe) against the kernel target.

I think the net_exit code might need to do a bit more with iSER. I'm going to look into that, then I'll merge some of these patches that fix earlier patches together, and get a new clean version of the set posted.

Chris Leech (3):
iscsi iser: fix iser, allow virtual endpoints again iscsi iser: direct network namespace support for endpoints iscsi iser: enable network namespace awareness in iser

 drivers/infiniband/ulp/iser/iscsi_iser.c | 13 ++++---
 drivers/scsi/iscsi_tcp.c                 | 10 ++----
 drivers/scsi/iscsi_tcp.h                 |  1 -
 drivers/scsi/libiscsi.c                  | 12 +++++++
 drivers/scsi/scsi_transport_iscsi.c      | 45 +++++++++++++++++++-----
 include/scsi/libiscsi.h                  |  4 +++
 include/scsi/scsi_transport_iscsi.h      |  9 ++++-
 7 files changed, 71 insertions(+), 23 deletions(-)
Signature · 1 line
2.39.2
maintainer
#9 lore raw

PATCH 1/1 iscsi iser: fix iser, allow virtual endpoints again

iSER creates endpoints before hosts and sessions, so we need to keep compatibility with virtual device paths and not always expect a parent host.

---
 drivers/scsi/scsi_transport_iscsi.c | 9 ++++++---
 include/scsi/scsi_transport_iscsi.h | 3 ++-
 2 files changed, 8 insertions(+), 4 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +6 -3
index 41f0de2165e0..b8e451a8c76c 100644
@@ -189,8 +189,10 @@ static struct net *iscsi_host_net(struct iscsi_cls_host *ihost)
 static struct net *iscsi_endpoint_net(struct iscsi_endpoint *ep)
 {
 	struct Scsi_Host *shost = iscsi_endpoint_to_shost(ep);
-	struct iscsi_cls_host *ihost = shost->shost_data;
-
+	struct iscsi_cls_host *ihost;
+	if (!shost)
+		return &init_net;
+	ihost = shost->shost_data;
 	return iscsi_host_net(ihost);
 }
 
@@ -252,7 +254,8 @@ iscsi_create_endpoint(struct Scsi_Host *shost, int dd_size)
 
 	ep->id = id;
 	ep->dev.class = &iscsi_endpoint_class;
-	ep->dev.parent = &shost->shost_gendev;
+	if (shost)
+		ep->dev.parent = &shost->shost_gendev;
 	dev_set_name(&ep->dev, "ep-%d", id);
 	err = device_register(&ep->dev);
         if (err)
include/scsi/scsi_transport_iscsi.h +2 -1
index d233618a17de..bb6734e900e0 100644
@@ -293,8 +293,9 @@ struct iscsi_cls_session {
 #define iscsi_session_to_shost(_session) \
 	dev_to_shost(_session->dev.parent)
 
+/* endpoints might not have a parent host (iSER) */
 #define iscsi_endpoint_to_shost(_ep) \
-	dev_to_shost(_ep->dev.parent)
+	dev_to_shost(&_ep->dev)
 
 extern struct net *iscsi_sess_net(struct iscsi_cls_session *session);
 
Signature · 1 line
2.39.2
maintainer
#10 lore raw

PATCH 1/1 iscsi iser: enable network namespace awareness in iser

In reply to Chris Leech

Move the logic to store the network namespace during virtual host creation (due to the way transport-class object setup callbacks function) from iscsi_tcp into libiscsi, and share it with iser.

---
 drivers/infiniband/ulp/iser/iscsi_iser.c |  7 ++++++-
 drivers/scsi/iscsi_tcp.c                 | 10 ++--------
 drivers/scsi/iscsi_tcp.h                 |  1 -
 drivers/scsi/libiscsi.c                  | 12 ++++++++++++
 include/scsi/libiscsi.h                  |  4 ++++
 5 files changed, 24 insertions(+), 10 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +6 -1
index ecb8aba1cee9..381f48a832ce 100644
@@ -646,6 +646,8 @@ __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;
@@ -653,6 +655,7 @@ __iscsi_iser_session_create(struct iscsi_endpoint *ep,
 		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;
 	}
@@ -1029,7 +1032,9 @@ static struct iscsi_transport iscsi_iser_transport = {
 
 	.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)
drivers/scsi/iscsi_tcp.c +2 -8
index 17f07ca2bbb8..3150d9c7a1ee 100644
@@ -947,7 +947,7 @@ iscsi_sw_tcp_session_create(struct net *net, uint16_t cmds_max,
 	shost->can_queue = rc;
 
 	tcp_sw_host = iscsi_host_priv(shost);
-	tcp_sw_host->net_ns = net;
+	iscsi_host_set_netns(shost, net);
 
 	if (iscsi_host_add(shost, NULL))
 		goto free_host;
@@ -1068,12 +1068,6 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
 	return 0;
 }
 
-static struct net *iscsi_sw_tcp_netns(struct Scsi_Host *shost)
-{
-	struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
-	return tcp_sw_host->net_ns;
-}
-
 static struct scsi_host_template iscsi_sw_tcp_sht = {
 	.module			= THIS_MODULE,
 	.name			= "iSCSI Initiator over TCP/IP",
@@ -1130,7 +1124,7 @@ static struct iscsi_transport iscsi_sw_tcp_transport = {
 	/* recovery */
 	.session_recovery_timedout = iscsi_session_recovery_timedout,
 	/* net namespace */
-	.get_netns		= iscsi_sw_tcp_netns,
+	.get_netns		= iscsi_host_get_netns,
 };
 
 static int __init iscsi_sw_tcp_init(void)
drivers/scsi/iscsi_tcp.h +0 -1
index f0020cb22f59..68e14a344904 100644
@@ -53,7 +53,6 @@ struct iscsi_sw_tcp_conn {
 
 struct iscsi_sw_tcp_host {
 	struct iscsi_session	*session;
-	struct net *net_ns;
 };
 
 struct iscsi_sw_tcp_hdrbuf {
drivers/scsi/libiscsi.c +12 -0
index 127f3d7f19dc..ca8856c24688 100644
@@ -3929,6 +3929,18 @@ 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");
include/scsi/libiscsi.h +4 -0
index e39fb0736ade..acd868b5f6ef 100644
@@ -383,6 +383,7 @@ struct iscsi_host {
 	int			state;
 
 	struct workqueue_struct	*workq;
+	struct net *net_ns;
 };
 
 /*
@@ -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.
  */
Signature · 1 line
2.39.2
maintainer
#11 lore raw

PATCH 1/1 iscsi iser: direct network namespace support for endpoints

In reply to Chris Leech

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

This is much like was done with sessions already for iscsi_tcp.

---
 drivers/infiniband/ulp/iser/iscsi_iser.c |  6 ++--
 drivers/scsi/scsi_transport_iscsi.c      | 38 +++++++++++++++++++-----
 include/scsi/scsi_transport_iscsi.h      |  6 ++++
 3 files changed, 40 insertions(+), 10 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +3 -3
index 49fbfeb49b34..ecb8aba1cee9 100644
@@ -813,7 +813,7 @@ 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)
 {
@@ -821,7 +821,7 @@ static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost,
 	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);
 
@@ -1027,7 +1027,7 @@ 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
 };
drivers/scsi/scsi_transport_iscsi.c +31 -7
index b8e451a8c76c..d41b4c1ad611 100644
@@ -190,6 +190,9 @@ 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;
@@ -228,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;
@@ -256,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)
@@ -283,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);
@@ -3279,10 +3297,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) {
@@ -3292,11 +3310,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;
include/scsi/scsi_transport_iscsi.h +6 -0
index bb6734e900e0..a540e085de8d 100644
@@ -127,6 +127,9 @@ struct iscsi_transport {
 	struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
 					      struct sockaddr *dst_addr,
 					      int non_blocking);
+	struct iscsi_endpoint *(*ep_connect_net) (struct net *net,
+					      struct sockaddr *dst_addr,
+					      int non_blocking);
 	int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
 	void (*ep_disconnect) (struct iscsi_endpoint *ep);
 	int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
@@ -321,6 +324,7 @@ struct iscsi_endpoint {
 	struct device dev;
 	int id;
 	struct iscsi_cls_conn *conn;
+	struct net *netns;		/* used if there's no parent shost */
 };
 
 struct iscsi_iface {
@@ -477,6 +481,8 @@ extern void iscsi_unblock_session(struct iscsi_cls_session *session);
 extern void iscsi_block_session(struct iscsi_cls_session *session);
 extern struct iscsi_endpoint *iscsi_create_endpoint(struct Scsi_Host *shost,
 						    int dd_size);
+extern struct iscsi_endpoint *iscsi_create_endpoint_net(struct net *net,
+						    int dd_size);
 extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
 extern struct iscsi_endpoint *iscsi_lookup_endpoint(struct net *net,
 						    u64 handle);
Signature · 1 line
2.39.2
author
#12 lore raw

RFC PATCH 3/9 iscsi: sysfs filtering by network namespace

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

This makes the iscsi_host, iscsi_session, iscsi_connection, iscsi_iface, and iscsi_endpoint transport class devices only visible in sysfs under a matching network namespace. The network namespace for all of these objects is tracked in the iscsi_cls_host structure.

---
 drivers/scsi/scsi_transport_iscsi.c | 124 ++++++++++++++++++++++++----
 include/scsi/scsi_transport_iscsi.h |   1 +
 2 files changed, 110 insertions(+), 15 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +109 -15
index 86bafdb862a5..2e2b291bce41 100644
@@ -181,9 +181,31 @@ static void iscsi_endpoint_release(struct device *dev)
 	kfree(ep);
 }
 
+static struct net *iscsi_host_net(struct iscsi_cls_host *ihost)
+{
+	return ihost->netns;
+}
+
+static struct net *iscsi_endpoint_net(struct iscsi_endpoint *ep)
+{
+	struct Scsi_Host *shost = iscsi_endpoint_to_shost(ep);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+
+	return iscsi_host_net(ihost);
+}
+
+static const void *iscsi_endpoint_namespace(const struct device *dev)
+{
+	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+
+	return iscsi_endpoint_net(ep);
+}
+
 static struct class iscsi_endpoint_class = {
 	.name = "iscsi_endpoint",
 	.dev_release = iscsi_endpoint_release,
+	.ns_type = &net_ns_type_operations,
+	.namespace = iscsi_endpoint_namespace,
 };
 
 static ssize_t
@@ -308,10 +330,26 @@ static void iscsi_iface_release(struct device *dev)
 	put_device(parent);
 }
 
+static struct net *iscsi_iface_net(struct iscsi_iface *iface)
+{
+	struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+
+	return iscsi_host_net(ihost);
+}
+
+static const void *iscsi_iface_namespace(const struct device *dev)
+{
+	struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
+
+	return iscsi_iface_net(iface);
+}
 
 static struct class iscsi_iface_class = {
 	.name = "iscsi_iface",
 	.dev_release = iscsi_iface_release,
+	.ns_type = &net_ns_type_operations,
+	.namespace = iscsi_iface_namespace,
 };
 
 #define ISCSI_IFACE_ATTR(_prefix, _name, _mode, _show, _store)	\
@@ -1565,6 +1603,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
 
 	memset(ihost, 0, sizeof(*ihost));
 	mutex_init(&ihost->mutex);
+	ihost->netns = &init_net;
 
 	iscsi_bsg_host_add(shost, ihost);
 	/* ignore any bsg add error - we just can't do sgio */
@@ -1582,23 +1621,78 @@ static int iscsi_remove_host(struct transport_container *tc,
 	return 0;
 }
 
-static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
-			       "iscsi_host",
-			       iscsi_setup_host,
-			       iscsi_remove_host,
-			       NULL);
+#define DECLARE_TRANSPORT_CLASS_NS(cls, nm, su, rm, cfg, ns, nslookup)	\
+struct transport_class cls = {						\
+	.class = {							\
+		.name = nm,						\
+		.ns_type = ns,						\
+		.namespace = nslookup,					\
+	},								\
+	.setup = su,							\
+	.remove = rm,							\
+	.configure = cfg,						\
+}
+
+static const void *iscsi_host_namespace(const struct device *dev)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(dev);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+
+	return iscsi_host_net(ihost);
+}
+
+static DECLARE_TRANSPORT_CLASS_NS(iscsi_host_class,
+				  "iscsi_host",
+				  iscsi_setup_host,
+				  iscsi_remove_host,
+				  NULL,
+				  &net_ns_type_operations,
+				  iscsi_host_namespace);
 
-static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
-			       "iscsi_session",
-			       NULL,
-			       NULL,
-			       NULL);
+static struct net *iscsi_sess_net(struct iscsi_cls_session *cls_session)
+{
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+
+	return iscsi_host_net(ihost);
+}
+
+static const void *iscsi_sess_namespace(const struct device *dev)
+{
+	struct iscsi_cls_session *cls_session = transport_class_to_session(dev);
+
+	return iscsi_sess_net(cls_session);
+}
+
+static DECLARE_TRANSPORT_CLASS_NS(iscsi_session_class,
+				  "iscsi_session",
+				  NULL,
+				  NULL,
+				  NULL,
+				  &net_ns_type_operations,
+				  iscsi_sess_namespace);
+
+static struct net *iscsi_conn_net(struct iscsi_cls_conn *cls_conn)
+{
+	struct iscsi_cls_session *cls_session = iscsi_conn_to_session(cls_conn);
+
+	return iscsi_sess_net(cls_session);
+}
+
+static const void *iscsi_conn_namespace(const struct device *dev)
+{
+	struct iscsi_cls_conn *cls_conn = transport_class_to_conn(dev);
+
+	return iscsi_conn_net(cls_conn);
+}
 
-static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
-			       "iscsi_connection",
-			       NULL,
-			       NULL,
-			       NULL);
+static DECLARE_TRANSPORT_CLASS_NS(iscsi_connection_class,
+				  "iscsi_connection",
+				  NULL,
+				  NULL,
+				  NULL,
+				  &net_ns_type_operations,
+				  iscsi_conn_namespace);
 
 struct iscsi_net {
 	struct sock *nls;
include/scsi/scsi_transport_iscsi.h +1 -0
index 268ccaac1c05..af0c5a15f316 100644
@@ -298,6 +298,7 @@ struct iscsi_cls_host {
 	struct request_queue *bsg_q;
 	uint32_t port_speed;
 	uint32_t port_state;
+	struct net *netns;
 };
 
 #define iscsi_job_to_shost(_job) \
Signature · 1 line
2.39.1
Reviewed-by on v1 3/9
#13 lore raw

Re: [RFC PATCH 3/9] iscsi: sysfs filtering by network namespace

Quoted 7 lines · Lee Duncan

From: Lee Duncan <[email protected]>

This makes the iscsi_host, iscsi_session, iscsi_connection, iscsi_iface, and iscsi_endpoint transport class devices only visible in sysfs under a matching network namespace. The network namespace for all of these objects is tracked in the iscsi_cls_host structure.

Quoted 7 lines
---
  drivers/scsi/scsi_transport_iscsi.c | 124 ++++++++++++++++++++++++----
  include/scsi/scsi_transport_iscsi.h |   1 +
  2 files changed, 110 insertions(+), 15 deletions(-)

Cheers,

Hannes

author
#14 lore raw

RFC PATCH 4/9 iscsi: make all iSCSI netlink multicast namespace aware

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

Make use of the per-net netlink sockets. Responses are sent back on the same socket/namespace the request was received on. Async events are reported on the socket/namespace stored in the iscsi_cls_host associated with the event.

---
 drivers/scsi/scsi_transport_iscsi.c | 92 +++++++++++++++++++----------
 1 file changed, 60 insertions(+), 32 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +60 -32
index 2e2b291bce41..230b43d34c5f 100644
@@ -2653,8 +2653,8 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt)
 }
 
 static int
-iscsi_multicast_netns(struct net *net, struct sk_buff *skb,
-		      uint32_t group, gfp_t gfp)
+iscsi_multicast_skb(struct net *net, struct sk_buff *skb,
+		    uint32_t group, gfp_t gfp)
 {
 	struct sock *nls;
 	struct iscsi_net *isn;
@@ -2665,17 +2665,10 @@ iscsi_multicast_netns(struct net *net, struct sk_buff *skb,
 }
 
 static int
-iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
-{
-	return iscsi_multicast_netns(&init_net, skb, group, gfp);
-}
-
-static int
-iscsi_unicast_skb(struct sk_buff *skb, u32 portid)
+iscsi_unicast_skb(struct net *net, struct sk_buff *skb, u32 portid)
 {
 	struct sock *nls;
 	struct iscsi_net *isn;
-	struct net *net = &init_net;
 
 	isn = net_generic(net, iscsi_net_id);
 	nls = isn->nls;
@@ -2690,6 +2683,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
 	struct iscsi_uevent *ev;
 	char *pdu;
 	struct iscsi_internal *priv;
+	struct net *net;
 	int len = nlmsg_total_size(sizeof(*ev) + sizeof(struct iscsi_hdr) +
 				   data_size);
 
@@ -2716,7 +2710,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
 	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
 	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
 
-	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
+	net = iscsi_conn_net(conn);
+	return iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 }
 EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
 
@@ -2727,6 +2722,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
 	struct nlmsghdr	*nlh;
 	struct sk_buff *skb;
 	struct iscsi_uevent *ev;
+	struct net *net;
 	int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
 	skb = alloc_skb(len, GFP_ATOMIC);
@@ -2751,7 +2747,8 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
 
 	memcpy((char *)ev + sizeof(*ev), data, data_size);
 
-	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
+	net = iscsi_host_net(shost->shost_data);
+	return iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
 }
 EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
 
@@ -2761,6 +2758,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
 	struct sk_buff	*skb;
 	struct iscsi_uevent *ev;
 	struct iscsi_internal *priv;
+	struct net *net;
 	int len = nlmsg_total_size(sizeof(*ev));
 	unsigned long flags;
 	int state;
@@ -2808,7 +2806,8 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
 	ev->r.connerror.cid = conn->cid;
 	ev->r.connerror.sid = iscsi_conn_get_sid(conn);
 
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
+	net = iscsi_conn_net(conn);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 
 	iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
 			      error);
@@ -2822,6 +2821,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
 	struct sk_buff  *skb;
 	struct iscsi_uevent *ev;
 	struct iscsi_internal *priv;
+	struct net *net;
 	int len = nlmsg_total_size(sizeof(*ev));
 
 	priv = iscsi_if_transport_lookup(conn->transport);
@@ -2842,7 +2842,9 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
 	ev->r.conn_login.state = state;
 	ev->r.conn_login.cid = conn->cid;
 	ev->r.conn_login.sid = iscsi_conn_get_sid(conn);
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
+
+	net = iscsi_conn_net(conn);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 
 	iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn login (%d)\n",
 			      state);
@@ -2853,11 +2855,17 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
 			   enum iscsi_host_event_code code, uint32_t data_size,
 			   uint8_t *data)
 {
+	struct Scsi_Host *shost;
+	struct net *net;
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
 	struct iscsi_uevent *ev;
 	int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
+	shost = scsi_host_lookup(host_no);
+	if (!shost)
+		return;
+
 	skb = alloc_skb(len, GFP_NOIO);
 	if (!skb) {
 		printk(KERN_ERR "gracefully ignored host event (%d):%d OOM\n",
@@ -2876,7 +2884,9 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
 	if (data_size)
 		memcpy((char *)ev + sizeof(*ev), data, data_size);
 
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
+	net = iscsi_host_net(shost->shost_data);
+	scsi_host_put(shost);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
 }
 EXPORT_SYMBOL_GPL(iscsi_post_host_event);
 
@@ -2884,11 +2894,17 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
 			   uint32_t status, uint32_t pid, uint32_t data_size,
 			   uint8_t *data)
 {
+	struct Scsi_Host *shost;
+	struct net *net;
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
 	struct iscsi_uevent *ev;
 	int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
+	shost = scsi_host_lookup(host_no);
+	if (!shost)
+		return;
+
 	skb = alloc_skb(len, GFP_NOIO);
 	if (!skb) {
 		printk(KERN_ERR "gracefully ignored ping comp: OOM\n");
@@ -2905,12 +2921,15 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
 	ev->r.ping_comp.data_size = data_size;
 	memcpy((char *)ev + sizeof(*ev), data, data_size);
 
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
+	net = iscsi_host_net(shost->shost_data);
+	scsi_host_put(shost);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
 }
 EXPORT_SYMBOL_GPL(iscsi_ping_comp_event);
 
 static int
-iscsi_if_send_reply(u32 portid, int type, void *payload, int size)
+iscsi_if_send_reply(struct net *net, u32 portid, int type,
+		    void *payload, int size)
 {
 	struct sk_buff	*skb;
 	struct nlmsghdr	*nlh;
@@ -2924,11 +2943,11 @@ iscsi_if_send_reply(u32 portid, int type, void *payload, int size)
 
 	nlh = __nlmsg_put(skb, 0, 0, type, (len - sizeof(*nlh)), 0);
 	memcpy(nlmsg_data(nlh), payload, size);
-	return iscsi_unicast_skb(skb, portid);
+	return iscsi_unicast_skb(net, skb, portid);
 }
 
 static int
-iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+iscsi_if_get_stats(struct net *net, struct iscsi_transport *transport, struct nlmsghdr *nlh)
 {
 	struct iscsi_uevent *ev = nlmsg_data(nlh);
 	struct iscsi_stats *stats;
@@ -2985,7 +3004,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 		skb_trim(skbstat, NLMSG_ALIGN(actual_size));
 		nlhstat->nlmsg_len = actual_size;
 
-		err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
+		err = iscsi_multicast_skb(net, skbstat, ISCSI_NL_GRP_ISCSID,
 					  GFP_ATOMIC);
 	} while (err < 0 && err != -ECONNREFUSED);
 
@@ -3005,6 +3024,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
 	struct iscsi_uevent *ev;
 	struct sk_buff  *skb;
 	struct nlmsghdr *nlh;
+	struct net *net;
 	int rc, len = nlmsg_total_size(sizeof(*ev));
 
 	priv = iscsi_if_transport_lookup(session->transport);
@@ -3049,7 +3069,8 @@ int iscsi_session_event(struct iscsi_cls_session *session,
 	 * this will occur if the daemon is not up, so we just warn
 	 * the user and when the daemon is restarted it will handle it
 	 */
-	rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
+	net = iscsi_sess_net(session);
+	rc = iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
 	if (rc == -ESRCH)
 		iscsi_cls_session_printk(KERN_ERR, session,
 					 "Cannot notify userspace of session "
@@ -3412,7 +3433,8 @@ iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 }
 
 static int
-iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+iscsi_get_chap(struct net *net, struct iscsi_transport *transport,
+	       struct nlmsghdr *nlh)
 {
 	struct iscsi_uevent *ev = nlmsg_data(nlh);
 	struct Scsi_Host *shost = NULL;
@@ -3471,7 +3493,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 		skb_trim(skbchap, NLMSG_ALIGN(actual_size));
 		nlhchap->nlmsg_len = actual_size;
 
-		err = iscsi_multicast_skb(skbchap, ISCSI_NL_GRP_ISCSID,
+		err = iscsi_multicast_skb(net, skbchap, ISCSI_NL_GRP_ISCSID,
 					  GFP_KERNEL);
 	} while (err < 0 && err != -ECONNREFUSED);
 
@@ -3818,7 +3840,8 @@ static int iscsi_logout_flashnode_sid(struct iscsi_transport *transport,
 }
 
 static int
-iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+iscsi_get_host_stats(struct net *net, struct iscsi_transport *transport,
+		     struct nlmsghdr *nlh)
 {
 	struct iscsi_uevent *ev = nlmsg_data(nlh);
 	struct Scsi_Host *shost = NULL;
@@ -3878,8 +3901,8 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 		skb_trim(skbhost_stats, NLMSG_ALIGN(actual_size));
 		nlhhost_stats->nlmsg_len = actual_size;
 
-		err = iscsi_multicast_skb(skbhost_stats, ISCSI_NL_GRP_ISCSID,
-					  GFP_KERNEL);
+		err = iscsi_multicast_skb(net, skbhost_stats,
+					  ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
 	} while (err < 0 && err != -ECONNREFUSED);
 
 exit_host_stats:
@@ -4001,7 +4024,8 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport,
 }
 
 static int
-iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
+iscsi_if_recv_msg(struct net *net, struct sk_buff *skb,
+		  struct nlmsghdr *nlh, uint32_t *group)
 {
 	int err = 0;
 	u32 portid;
@@ -4096,7 +4120,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 		err = iscsi_if_transport_conn(transport, nlh);
 		break;
 	case ISCSI_UEVENT_GET_STATS:
-		err = iscsi_if_get_stats(transport, nlh);
+		err = iscsi_if_get_stats(net, transport, nlh);
 		break;
 	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
 	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
@@ -4121,7 +4145,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 		err = iscsi_send_ping(transport, ev);
 		break;
 	case ISCSI_UEVENT_GET_CHAP:
-		err = iscsi_get_chap(transport, nlh);
+		err = iscsi_get_chap(net, transport, nlh);
 		break;
 	case ISCSI_UEVENT_DELETE_CHAP:
 		err = iscsi_delete_chap(transport, ev);
@@ -4152,7 +4176,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 				     nlmsg_attrlen(nlh, sizeof(*ev)));
 		break;
 	case ISCSI_UEVENT_GET_HOST_STATS:
-		err = iscsi_get_host_stats(transport, nlh);
+		err = iscsi_get_host_stats(net, transport, nlh);
 		break;
 	default:
 		err = -ENOSYS;
@@ -4170,6 +4194,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 static void
 iscsi_if_rx(struct sk_buff *skb)
 {
+	struct sock *sk = skb->sk;
+	struct net *net = sock_net(sk);
 	u32 portid = NETLINK_CB(skb).portid;
 
 	mutex_lock(&rx_queue_mutex);
@@ -4192,7 +4218,7 @@ iscsi_if_rx(struct sk_buff *skb)
 		if (rlen > skb->len)
 			rlen = skb->len;
 
-		err = iscsi_if_recv_msg(skb, nlh, &group);
+		err = iscsi_if_recv_msg(net, skb, nlh, &group);
 		if (err) {
 			ev->type = ISCSI_KEVENT_IF_ERROR;
 			ev->iferror = err;
@@ -4208,7 +4234,9 @@ iscsi_if_rx(struct sk_buff *skb)
 				break;
 			if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
 				break;
-			err = iscsi_if_send_reply(portid, nlh->nlmsg_type,
+			if (ev->type == ISCSI_UEVENT_GET_HOST_STATS && !err)
+				break;
+			err = iscsi_if_send_reply(net, portid, nlh->nlmsg_type,
 						  ev, sizeof(*ev));
 			if (err == -EAGAIN && --retries < 0) {
 				printk(KERN_WARNING "Send reply failed, error %d\n", err);
Signature · 1 line
2.39.1
Reviewed-by on v1 4/9
#15 lore raw

Re: [RFC PATCH 4/9] iscsi: make all iSCSI netlink multicast namespace aware

Quoted 322 lines · Lee Duncan

From: Lee Duncan <[email protected]>

Make use of the per-net netlink sockets. Responses are sent back on the same socket/namespace the request was received on. Async events are reported on the socket/namespace stored in the iscsi_cls_host associated with the event.

---
  drivers/scsi/scsi_transport_iscsi.c | 92 +++++++++++++++++++----------
  1 file changed, 60 insertions(+), 32 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +57 -31
index 2e2b291bce41..230b43d34c5f 100644
@@ -2653,8 +2653,8 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt)
  }
 
  static int
-iscsi_multicast_netns(struct net *net, struct sk_buff *skb,
-		      uint32_t group, gfp_t gfp)
+iscsi_multicast_skb(struct net *net, struct sk_buff *skb,
+		    uint32_t group, gfp_t gfp)
  {
  	struct sock *nls;
  	struct iscsi_net *isn;
@@ -2665,17 +2665,10 @@ iscsi_multicast_netns(struct net *net, struct sk_buff *skb,
  }
 
  static int
-iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
-{
-	return iscsi_multicast_netns(&init_net, skb, group, gfp);
-}
-
-static int
-iscsi_unicast_skb(struct sk_buff *skb, u32 portid)
+iscsi_unicast_skb(struct net *net, struct sk_buff *skb, u32 portid)
  {
  	struct sock *nls;
  	struct iscsi_net *isn;
-	struct net *net = &init_net;
 
  	isn = net_generic(net, iscsi_net_id);
  	nls = isn->nls;
@@ -2690,6 +2683,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
  	struct iscsi_uevent *ev;
  	char *pdu;
  	struct iscsi_internal *priv;
+	struct net *net;
  	int len = nlmsg_total_size(sizeof(*ev) + sizeof(struct iscsi_hdr) +
  				   data_size);
 
@@ -2716,7 +2710,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
  	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
  	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
 
-	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
+	net = iscsi_conn_net(conn);
+	return iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
  }
  EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
 
@@ -2727,6 +2722,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
  	struct nlmsghdr	*nlh;
  	struct sk_buff *skb;
  	struct iscsi_uevent *ev;
+	struct net *net;
  	int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
  	skb = alloc_skb(len, GFP_ATOMIC);
@@ -2751,7 +2747,8 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
 
  	memcpy((char *)ev + sizeof(*ev), data, data_size);
 
-	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
+	net = iscsi_host_net(shost->shost_data);
+	return iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
  }
  EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
 
@@ -2761,6 +2758,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
  	struct sk_buff	*skb;
  	struct iscsi_uevent *ev;
  	struct iscsi_internal *priv;
+	struct net *net;
  	int len = nlmsg_total_size(sizeof(*ev));
  	unsigned long flags;
  	int state;
@@ -2808,7 +2806,8 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
  	ev->r.connerror.cid = conn->cid;
  	ev->r.connerror.sid = iscsi_conn_get_sid(conn);
 
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
+	net = iscsi_conn_net(conn);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 
  	iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
  			      error);
@@ -2822,6 +2821,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
  	struct sk_buff  *skb;
  	struct iscsi_uevent *ev;
  	struct iscsi_internal *priv;
+	struct net *net;
  	int len = nlmsg_total_size(sizeof(*ev));
 
  	priv = iscsi_if_transport_lookup(conn->transport);
@@ -2842,7 +2842,9 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
  	ev->r.conn_login.state = state;
  	ev->r.conn_login.cid = conn->cid;
  	ev->r.conn_login.sid = iscsi_conn_get_sid(conn);
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
+
+	net = iscsi_conn_net(conn);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 
  	iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn login (%d)\n",
  			      state);
@@ -2853,11 +2855,17 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
  			   enum iscsi_host_event_code code, uint32_t data_size,
  			   uint8_t *data)
  {
+	struct Scsi_Host *shost;
+	struct net *net;
  	struct nlmsghdr *nlh;
  	struct sk_buff *skb;
  	struct iscsi_uevent *ev;
  	int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
+	shost = scsi_host_lookup(host_no);
+	if (!shost)
+		return;
+
  	skb = alloc_skb(len, GFP_NOIO);
  	if (!skb) {
  		printk(KERN_ERR "gracefully ignored host event (%d):%d OOM\n",
@@ -2876,7 +2884,9 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
  	if (data_size)
  		memcpy((char *)ev + sizeof(*ev), data, data_size);
 
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
+	net = iscsi_host_net(shost->shost_data);
+	scsi_host_put(shost);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
  }
  EXPORT_SYMBOL_GPL(iscsi_post_host_event);
 
@@ -2884,11 +2894,17 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
  			   uint32_t status, uint32_t pid, uint32_t data_size,
  			   uint8_t *data)
  {
+	struct Scsi_Host *shost;
+	struct net *net;
  	struct nlmsghdr *nlh;
  	struct sk_buff *skb;
  	struct iscsi_uevent *ev;
  	int len = nlmsg_total_size(sizeof(*ev) + data_size);
 
+	shost = scsi_host_lookup(host_no);
+	if (!shost)
+		return;
+
  	skb = alloc_skb(len, GFP_NOIO);
  	if (!skb) {
  		printk(KERN_ERR "gracefully ignored ping comp: OOM\n");
@@ -2905,12 +2921,15 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
  	ev->r.ping_comp.data_size = data_size;
  	memcpy((char *)ev + sizeof(*ev), data, data_size);
 
-	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
+	net = iscsi_host_net(shost->shost_data);
+	scsi_host_put(shost);
+	iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
  }
  EXPORT_SYMBOL_GPL(iscsi_ping_comp_event);
 
  static int
-iscsi_if_send_reply(u32 portid, int type, void *payload, int size)
+iscsi_if_send_reply(struct net *net, u32 portid, int type,
+		    void *payload, int size)
  {
  	struct sk_buff	*skb;
  	struct nlmsghdr	*nlh;
@@ -2924,11 +2943,11 @@ iscsi_if_send_reply(u32 portid, int type, void *payload, int size)
 
  	nlh = __nlmsg_put(skb, 0, 0, type, (len - sizeof(*nlh)), 0);
  	memcpy(nlmsg_data(nlh), payload, size);
-	return iscsi_unicast_skb(skb, portid);
+	return iscsi_unicast_skb(net, skb, portid);
  }
 
  static int
-iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+iscsi_if_get_stats(struct net *net, struct iscsi_transport *transport, struct nlmsghdr *nlh)
  {
  	struct iscsi_uevent *ev = nlmsg_data(nlh);
  	struct iscsi_stats *stats;
@@ -2985,7 +3004,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
  		skb_trim(skbstat, NLMSG_ALIGN(actual_size));
  		nlhstat->nlmsg_len = actual_size;
 
-		err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
+		err = iscsi_multicast_skb(net, skbstat, ISCSI_NL_GRP_ISCSID,
  					  GFP_ATOMIC);
  	} while (err < 0 && err != -ECONNREFUSED);
 
@@ -3005,6 +3024,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
  	struct iscsi_uevent *ev;
  	struct sk_buff  *skb;
  	struct nlmsghdr *nlh;
+	struct net *net;
  	int rc, len = nlmsg_total_size(sizeof(*ev));
 
  	priv = iscsi_if_transport_lookup(session->transport);
@@ -3049,7 +3069,8 @@ int iscsi_session_event(struct iscsi_cls_session *session,
  	 * this will occur if the daemon is not up, so we just warn
  	 * the user and when the daemon is restarted it will handle it
  	 */
-	rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
+	net = iscsi_sess_net(session);
+	rc = iscsi_multicast_skb(net, skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
  	if (rc == -ESRCH)
  		iscsi_cls_session_printk(KERN_ERR, session,
  					 "Cannot notify userspace of session "
@@ -3412,7 +3433,8 @@ iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
  }
 
  static int
-iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+iscsi_get_chap(struct net *net, struct iscsi_transport *transport,
+	       struct nlmsghdr *nlh)
  {
  	struct iscsi_uevent *ev = nlmsg_data(nlh);
  	struct Scsi_Host *shost = NULL;
@@ -3471,7 +3493,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
  		skb_trim(skbchap, NLMSG_ALIGN(actual_size));
  		nlhchap->nlmsg_len = actual_size;
 
-		err = iscsi_multicast_skb(skbchap, ISCSI_NL_GRP_ISCSID,
+		err = iscsi_multicast_skb(net, skbchap, ISCSI_NL_GRP_ISCSID,
  					  GFP_KERNEL);
  	} while (err < 0 && err != -ECONNREFUSED);
 
@@ -3818,7 +3840,8 @@ static int iscsi_logout_flashnode_sid(struct iscsi_transport *transport,
  }
 
  static int
-iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+iscsi_get_host_stats(struct net *net, struct iscsi_transport *transport,
+		     struct nlmsghdr *nlh)
  {
  	struct iscsi_uevent *ev = nlmsg_data(nlh);
  	struct Scsi_Host *shost = NULL;
@@ -3878,8 +3901,8 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
  		skb_trim(skbhost_stats, NLMSG_ALIGN(actual_size));
  		nlhhost_stats->nlmsg_len = actual_size;
 
-		err = iscsi_multicast_skb(skbhost_stats, ISCSI_NL_GRP_ISCSID,
-					  GFP_KERNEL);
+		err = iscsi_multicast_skb(net, skbhost_stats,
+					  ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
  	} while (err < 0 && err != -ECONNREFUSED);
 
  exit_host_stats:
@@ -4001,7 +4024,8 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport,
  }
 
  static int
-iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
+iscsi_if_recv_msg(struct net *net, struct sk_buff *skb,
+		  struct nlmsghdr *nlh, uint32_t *group)
  {
  	int err = 0;
  	u32 portid;
@@ -4096,7 +4120,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
  		err = iscsi_if_transport_conn(transport, nlh);
  		break;
  	case ISCSI_UEVENT_GET_STATS:
-		err = iscsi_if_get_stats(transport, nlh);
+		err = iscsi_if_get_stats(net, transport, nlh);
  		break;
  	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
  	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
@@ -4121,7 +4145,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
  		err = iscsi_send_ping(transport, ev);
  		break;
  	case ISCSI_UEVENT_GET_CHAP:
-		err = iscsi_get_chap(transport, nlh);
+		err = iscsi_get_chap(net, transport, nlh);
  		break;
  	case ISCSI_UEVENT_DELETE_CHAP:
  		err = iscsi_delete_chap(transport, ev);
@@ -4152,7 +4176,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
  				     nlmsg_attrlen(nlh, sizeof(*ev)));
  		break;
  	case ISCSI_UEVENT_GET_HOST_STATS:
-		err = iscsi_get_host_stats(transport, nlh);
+		err = iscsi_get_host_stats(net, transport, nlh);
  		break;
  	default:
  		err = -ENOSYS;
@@ -4170,6 +4194,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
  static void
  iscsi_if_rx(struct sk_buff *skb)
  {
+	struct sock *sk = skb->sk;
+	struct net *net = sock_net(sk);
  	u32 portid = NETLINK_CB(skb).portid;
 
  	mutex_lock(&rx_queue_mutex);
@@ -4192,7 +4218,7 @@ iscsi_if_rx(struct sk_buff *skb)
  		if (rlen > skb->len)
  			rlen = skb->len;
 
-		err = iscsi_if_recv_msg(skb, nlh, &group);
+		err = iscsi_if_recv_msg(net, skb, nlh, &group);
  		if (err) {
  			ev->type = ISCSI_KEVENT_IF_ERROR;
  			ev->iferror = err;

drivers/scsi/scsi_transport_iscsi.c iscsi_if_rx(struct sk_buff *skb) · line 4242

Quoted 10 lines
drivers/scsi/scsi_transport_iscsi.c +3 -1
@@ -4208,7 +4234,9 @@ iscsi_if_rx(struct sk_buff *skb)
  				break;
  			if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
  				break;
-			err = iscsi_if_send_reply(portid, nlh->nlmsg_type,
+			if (ev->type == ISCSI_UEVENT_GET_HOST_STATS && !err)
+				break;
+			err = iscsi_if_send_reply(net, portid, nlh->nlmsg_type,
  						  ev, sizeof(*ev));
  			if (err == -EAGAIN && --retries < 0) {
  				printk(KERN_WARNING "Send reply failed, error %d\n", err);

As discussed with Lee: you should tear down sessions related to this namespace from the pernet ->exit callback, otherwise you end up with session which can no longer been reached as the netlink socket is gone.

Might be done in an additional patch, though.
If you do you can add:

to this patch.

Cheers,

Hannes

maintainer
#16 lore raw

PATCH 10/11 iscsi: make session and connection lists per-net

Eliminate the comparisions on list lookups, and it will make it easier to shut down session on net namespace exit in the next patch.

---
 drivers/scsi/scsi_transport_iscsi.c | 104 ++++++++++++++++------------
 1 file changed, 61 insertions(+), 43 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +61 -43
index 9a176ea0d866..3a068d8eca2d 100644
@@ -1734,17 +1734,16 @@ static DECLARE_TRANSPORT_CLASS_NS(iscsi_connection_class,
 
 struct iscsi_net {
 	struct sock *nls;
+	spinlock_t sesslock;
+	struct list_head sesslist;
+	spinlock_t connlock;
+	struct list_head connlist;
+	struct list_head connlist_err;
 };
 
 static int iscsi_net_id __read_mostly;
 static DEFINE_MUTEX(rx_queue_mutex);
 
-static LIST_HEAD(sesslist);
-static DEFINE_SPINLOCK(sesslock);
-static LIST_HEAD(connlist);
-static LIST_HEAD(connlist_err);
-static DEFINE_SPINLOCK(connlock);
-
 static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn)
 {
 	struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent);
@@ -1759,19 +1758,18 @@ static struct iscsi_cls_session *iscsi_session_lookup(struct net *net,
 {
 	unsigned long flags;
 	struct iscsi_cls_session *sess;
-	struct net *ns;
+	struct iscsi_net *isn;
 
-	spin_lock_irqsave(&sesslock, flags);
-	list_for_each_entry(sess, &sesslist, sess_list) {
+	isn = net_generic(net, iscsi_net_id);
+
+	spin_lock_irqsave(&isn->sesslock, flags);
+	list_for_each_entry(sess, &isn->sesslist, sess_list) {
 		if (sess->sid == sid) {
-			ns = iscsi_sess_net(sess);
-			if (ns != net)
-				continue;
-			spin_unlock_irqrestore(&sesslock, flags);
+			spin_unlock_irqrestore(&isn->sesslock, flags);
 			return sess;
 		}
 	}
-	spin_unlock_irqrestore(&sesslock, flags);
+	spin_unlock_irqrestore(&isn->sesslock, flags);
 	return NULL;
 }
 
@@ -1783,19 +1781,18 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(struct net *net, uint32_t sid,
 {
 	unsigned long flags;
 	struct iscsi_cls_conn *conn;
-	struct net *ns;
+	struct iscsi_net *isn;
 
-	spin_lock_irqsave(&connlock, flags);
-	list_for_each_entry(conn, &connlist, conn_list) {
+	isn = net_generic(net, iscsi_net_id);
+
+	spin_lock_irqsave(&isn->connlock, flags);
+	list_for_each_entry(conn, &isn->connlist, conn_list) {
 		if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) {
-			ns = iscsi_conn_net(conn);
-			if (ns != net)
-				continue;
-			spin_unlock_irqrestore(&connlock, flags);
+			spin_unlock_irqrestore(&isn->connlock, flags);
 			return conn;
 		}
 	}
-	spin_unlock_irqrestore(&connlock, flags);
+	spin_unlock_irqrestore(&isn->connlock, flags);
 	return NULL;
 }
 
@@ -2207,6 +2204,9 @@ EXPORT_SYMBOL_GPL(iscsi_alloc_session);
 int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
 {
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+	struct net *net = iscsi_host_net(ihost);
+	struct iscsi_net *isn = net_generic(net, iscsi_net_id);
 	unsigned long flags;
 	int id = 0;
 	int err;
@@ -2250,9 +2250,9 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
 		goto release_dev;
 	}
 
-	spin_lock_irqsave(&sesslock, flags);
-	list_add(&session->sess_list, &sesslist);
-	spin_unlock_irqrestore(&sesslock, flags);
+	spin_lock_irqsave(&isn->sesslock, flags);
+	list_add(&session->sess_list, &isn->sesslist);
+	spin_unlock_irqrestore(&isn->sesslock, flags);
 
 	iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
 	ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n");
@@ -2322,15 +2322,17 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
 
 void iscsi_remove_session(struct iscsi_cls_session *session)
 {
+	struct net *net = iscsi_sess_net(session);
+	struct iscsi_net *isn = net_generic(net, iscsi_net_id);
 	unsigned long flags;
 	int err;
 
 	ISCSI_DBG_TRANS_SESSION(session, "Removing session\n");
 
-	spin_lock_irqsave(&sesslock, flags);
+	spin_lock_irqsave(&isn->sesslock, flags);
 	if (!list_empty(&session->sess_list))
 		list_del(&session->sess_list);
-	spin_unlock_irqrestore(&sesslock, flags);
+	spin_unlock_irqrestore(&isn->sesslock, flags);
 
 	if (!cancel_work_sync(&session->block_work))
 		cancel_delayed_work_sync(&session->recovery_work);
@@ -2541,20 +2543,22 @@ static int iscsi_iter_force_destroy_conn_fn(struct device *dev, void *data)
 void iscsi_force_destroy_session(struct iscsi_cls_session *session)
 {
 	struct iscsi_transport *transport = session->transport;
+	struct net *net = iscsi_sess_net(session);
+	struct iscsi_net *isn = net_generic(net, iscsi_net_id);
 	unsigned long flags;
 
 	WARN_ON_ONCE(system_state == SYSTEM_RUNNING);
 
-	spin_lock_irqsave(&sesslock, flags);
+	spin_lock_irqsave(&isn->sesslock, flags);
 	if (list_empty(&session->sess_list)) {
-		spin_unlock_irqrestore(&sesslock, flags);
+		spin_unlock_irqrestore(&isn->sesslock, flags);
 		/*
 		 * Conn/ep is already freed. Session is being torn down via
 		 * async path. For shutdown we don't care about it so return.
 		 */
 		return;
 	}
-	spin_unlock_irqrestore(&sesslock, flags);
+	spin_unlock_irqrestore(&isn->sesslock, flags);
 
 	device_for_each_child(&session->dev, NULL,
 			      iscsi_iter_force_destroy_conn_fn);
@@ -2625,6 +2629,8 @@ int iscsi_add_conn(struct iscsi_cls_conn *conn)
 	int err;
 	unsigned long flags;
 	struct iscsi_cls_session *session = iscsi_dev_to_session(conn->dev.parent);
+	struct net *net = iscsi_sess_net(session);
+	struct iscsi_net *isn = net_generic(net, iscsi_net_id);
 
 	err = device_add(&conn->dev);
 	if (err) {
@@ -2640,9 +2646,9 @@ int iscsi_add_conn(struct iscsi_cls_conn *conn)
 		return err;
 	}
 
-	spin_lock_irqsave(&connlock, flags);
-	list_add(&conn->conn_list, &connlist);
-	spin_unlock_irqrestore(&connlock, flags);
+	spin_lock_irqsave(&isn->connlock, flags);
+	list_add(&conn->conn_list, &isn->connlist);
+	spin_unlock_irqrestore(&isn->connlock, flags);
 
 	return 0;
 }
@@ -2657,11 +2663,14 @@ EXPORT_SYMBOL_GPL(iscsi_add_conn);
  */
 void iscsi_remove_conn(struct iscsi_cls_conn *conn)
 {
+	struct net *net = iscsi_conn_net(conn);
+	struct iscsi_net *isn = net_generic(net, iscsi_net_id);
+
 	unsigned long flags;
 
-	spin_lock_irqsave(&connlock, flags);
+	spin_lock_irqsave(&isn->connlock, flags);
 	list_del(&conn->conn_list);
-	spin_unlock_irqrestore(&connlock, flags);
+	spin_unlock_irqrestore(&isn->connlock, flags);
 
 	transport_unregister_device(&conn->dev);
 	device_del(&conn->dev);
@@ -3432,20 +3441,21 @@ iscsi_set_path(struct net *net, struct iscsi_transport *transport,
 	return err;
 }
 
-static int iscsi_session_has_conns(int sid)
+static int iscsi_session_has_conns(struct net *net, int sid)
 {
+	struct iscsi_net *isn = net_generic(net, iscsi_net_id);
 	struct iscsi_cls_conn *conn;
 	unsigned long flags;
 	int found = 0;
 
-	spin_lock_irqsave(&connlock, flags);
-	list_for_each_entry(conn, &connlist, conn_list) {
+	spin_lock_irqsave(&isn->connlock, flags);
+	list_for_each_entry(conn, &isn->connlist, conn_list) {
 		if (iscsi_conn_get_sid(conn) == sid) {
 			found = 1;
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&connlock, flags);
+	spin_unlock_irqrestore(&isn->connlock, flags);
 
 	return found;
 }
@@ -4157,7 +4167,7 @@ iscsi_if_recv_msg(struct net *net, struct sk_buff *skb,
 		session = iscsi_session_lookup(net, ev->u.d_session.sid);
 		if (!session)
 			err = -EINVAL;
-		else if (iscsi_session_has_conns(ev->u.d_session.sid))
+		else if (iscsi_session_has_conns(net, ev->u.d_session.sid))
 			err = -EBUSY;
 		else
 			transport->destroy_session(session);
@@ -4166,15 +4176,16 @@ iscsi_if_recv_msg(struct net *net, struct sk_buff *skb,
 		session = iscsi_session_lookup(net, ev->u.d_session.sid);
 		if (!session)
 			err = -EINVAL;
-		else if (iscsi_session_has_conns(ev->u.d_session.sid))
+		else if (iscsi_session_has_conns(net, ev->u.d_session.sid))
 			err = -EBUSY;
 		else {
+			struct iscsi_net *isn = net_generic(net, iscsi_net_id);
 			unsigned long flags;
 
 			/* Prevent this session from being found again */
-			spin_lock_irqsave(&sesslock, flags);
+			spin_lock_irqsave(&isn->sesslock, flags);
 			list_del_init(&session->sess_list);
-			spin_unlock_irqrestore(&sesslock, flags);
+			spin_unlock_irqrestore(&isn->sesslock, flags);
 
 			queue_work(system_unbound_wq, &session->destroy_work);
 		}
@@ -5176,6 +5187,13 @@ static int __net_init iscsi_net_init(struct net *net)
 	if (!nls)
 		return -ENOMEM;
 	isn = net_generic(net, iscsi_net_id);
+
+	INIT_LIST_HEAD(&isn->sesslist);
+	spin_lock_init(&isn->sesslock);
+	INIT_LIST_HEAD(&isn->connlist);
+	INIT_LIST_HEAD(&isn->connlist_err);
+	spin_lock_init(&isn->connlock);
+
 	isn->nls = nls;
 	return 0;
 }
Signature · 1 line
2.39.2
Reviewed-by on v1 10/11
#17 lore raw

Re: [PATCH 10/11] iscsi: make session and connection lists per-net

Quoted 8 lines · Chris Leech

Eliminate the comparisions on list lookups, and it will make it easier to shut down session on net namespace exit in the next patch.

---
  drivers/scsi/scsi_transport_iscsi.c | 104 ++++++++++++++++------------
  1 file changed, 61 insertions(+), 43 deletions(-)

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke                Kernel Storage Architect
[email protected]                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman
maintainer
#18 lore raw

Re: [RFC PATCH 4/9] iscsi: make all iSCSI netlink multicast namespace aware

In reply to Hannes Reinecke
Quoted 4 lines

As discussed with Lee: you should tear down sessions related to this namespace from the pernet ->exit callback, otherwise you end up with session which can no longer been reached as the netlink socket is gone.

These two follow on changes handle removing active sesions when the namespace exits. Tested with iscsi_tcp and seems to be working for me.

Chris Leech (2):
iscsi: make session and connection lists per-net
iscsi: force destroy sesions when a network namespace exits

 drivers/scsi/scsi_transport_iscsi.c | 122 ++++++++++++++++++----------
 1 file changed, 79 insertions(+), 43 deletions(-)
Signature · 1 line
2.39.2
#19 lore raw

Re: [RFC PATCH 4/9] iscsi: make all iSCSI netlink multicast namespace aware

Quoted 8 lines · Chris Leech
Quoted 4 lines

As discussed with Lee: you should tear down sessions related to this namespace from the pernet ->exit callback, otherwise you end up with session which can no longer been reached as the netlink socket is gone.

These two follow on changes handle removing active sesions when the namespace exits. Tested with iscsi_tcp and seems to be working for me.

Quoted 7 lines

Chris Leech (2):
iscsi: make session and connection lists per-net
iscsi: force destroy sesions when a network namespace exits

  drivers/scsi/scsi_transport_iscsi.c | 122 ++++++++++++++++++----------
  1 file changed, 79 insertions(+), 43 deletions(-)

Thanks a lot!
That's precisely what I had been looking for.

But you really shouldn't have mentioned iSCSI offloads; that was too large an opening to _not_ comment on :-)

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke                Kernel Storage Architect
[email protected]                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman
maintainer
#20 lore raw

PATCH 11/11 iscsi: force destroy sesions when a network namespace exits

In reply to Hannes Reinecke

The namespace is gone, so there is no userspace to clean up. Force close all the sessions.

This should be enough for software transports, there's no implementation of migrating physical iSCSI hosts between network namespaces currently.

---
 drivers/scsi/scsi_transport_iscsi.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/scsi/scsi_transport_iscsi.c +18 -0
index 3a068d8eca2d..8fafa8f0e0df 100644
@@ -5200,9 +5200,27 @@ static int __net_init iscsi_net_init(struct net *net)
 
 static void __net_exit iscsi_net_exit(struct net *net)
 {
+	struct iscsi_cls_session *session, *tmp;
+	struct iscsi_transport *transport;
 	struct iscsi_net *isn;
+	unsigned long flags;
+	LIST_HEAD(sessions);
 
 	isn = net_generic(net, iscsi_net_id);
+
+	/* force session destruction, there is no userspace anymore */
+	spin_lock_irqsave(&isn->sesslock, flags);
+	list_for_each_entry_safe(session, tmp, &isn->sesslist, sess_list) {
+		list_move_tail(&session->sess_list, &sessions);
+	}
+	spin_unlock_irqrestore(&isn->sesslock, flags);
+	list_for_each_entry_safe(session, tmp, &sessions, sess_list) {
+		device_for_each_child(&session->dev, NULL,
+				      iscsi_iter_force_destroy_conn_fn);
+		transport = session->transport;
+		transport->destroy_session(session);
+	}
+
 	netlink_kernel_release(isn->nls);
 	isn->nls = NULL;
 }
Signature · 1 line
2.39.2
Reviewed-by on v1 11/11
#21 lore raw

Re: [PATCH 11/11] iscsi: force destroy sesions when a network namespace exits

Quoted 6 lines · Chris Leech

The namespace is gone, so there is no userspace to clean up. Force close all the sessions.

This should be enough for software transports, there's no implementation of migrating physical iSCSI hosts between network namespaces currently.

Ah, you shouldn't have mentioned that.
(Not quite sure how being namespace-aware relates to migration, though.) We should be checking/modifying the iSCSI offload drivers, too. But maybe with a later patch.

Quoted 5 lines
---
  drivers/scsi/scsi_transport_iscsi.c | 18 ++++++++++++++++++
  1 file changed, 18 insertions(+)

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke                Kernel Storage Architect
[email protected]                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman
maintainer
#22 lore raw

Re: [PATCH 11/11] iscsi: force destroy sesions when a network namespace exits

Quoted 11 lines · Hannes Reinecke
Quoted 6 lines · Chris Leech

The namespace is gone, so there is no userspace to clean up. Force close all the sessions.

This should be enough for software transports, there's no implementation of migrating physical iSCSI hosts between network namespaces currently.

Ah, you shouldn't have mentioned that.
(Not quite sure how being namespace-aware relates to migration, though.) We should be checking/modifying the iSCSI offload drivers, too. But maybe with a later patch.

I shouldn't have left that opening ;-)

The idea with this design is to keep everything rooted on the iscsi_host, and for physical HBAs those stay assigned to init_net. With this patch set, offload drivers remain unusable in a net namespace other than init_net. They simply are not visible.

By migration, I was implying the possibilty of assigment of an HBA iscsi_host into a namespace like you can do with a network interface. Such an iscsi_host would then need to be migrated back to init_net on namespace exit.

I don't think it works to try and share an iscsi_host across namespaces, and manage different sessions. The iSCSI HBAs have a limited number of network configurations, exposed as iscsi_iface objects, and I don't want to go down the road of figuring out how to share those.

- Chris

#23 lore raw

Re: [PATCH 11/11] iscsi: force destroy sesions when a network namespace exits

Quoted 25 lines · Chris Leech
Quoted 11 lines · Hannes Reinecke
Quoted 6 lines · Chris Leech

The namespace is gone, so there is no userspace to clean up. Force close all the sessions.

This should be enough for software transports, there's no implementation of migrating physical iSCSI hosts between network namespaces currently.

Ah, you shouldn't have mentioned that.
(Not quite sure how being namespace-aware relates to migration, though.) We should be checking/modifying the iSCSI offload drivers, too. But maybe with a later patch.

I shouldn't have left that opening ;-)

The idea with this design is to keep everything rooted on the iscsi_host, and for physical HBAs those stay assigned to init_net. With this patch set, offload drivers remain unusable in a net namespace other than init_net. They simply are not visible.

By migration, I was implying the possibilty of assigment of an HBA iscsi_host into a namespace like you can do with a network interface. Such an iscsi_host would then need to be migrated back to init_net on namespace exit.

Quoted 5 lines

I don't think it works to try and share an iscsi_host across namespaces, and manage different sessions. The iSCSI HBAs have a limited number of network configurations, exposed as iscsi_iface objects, and I don't want to go down the road of figuring out how to share those.

Ah, yes, indeed.

Quite some iSCSI offloads create the network session internally (or don't even have one), so making them namespace aware will be tricky.

But then I guess we should avoid creating offload sessions from other namespaces; preferably by a patch for the kernel such that userspace can run unmodified.

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke                Kernel Storage Architect
[email protected]                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman
author
#24 lore raw

RFC PATCH 5/9 iscsi: set netns for iscsi_tcp hosts

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

This lets iscsi_tcp operate in multiple namespaces. It uses current during session creation to find the net namespace, but it might be better to manage to pass it along from the iscsi netlink socket.

---
 drivers/scsi/iscsi_tcp.c            | 7 +++++++
 drivers/scsi/scsi_transport_iscsi.c | 7 ++++++-
 include/scsi/scsi_transport_iscsi.h | 1 +
 3 files changed, 14 insertions(+), 1 deletion(-)
drivers/scsi/iscsi_tcp.c +7 -0
index 0454d94e8cf0..22e7a5c93627 100644
@@ -1069,6 +1069,11 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
 	return 0;
 }
 
+static struct net *iscsi_sw_tcp_netns(struct Scsi_Host *shost)
+{
+	return current->nsproxy->net_ns;
+}
+
 static struct scsi_host_template iscsi_sw_tcp_sht = {
 	.module			= THIS_MODULE,
 	.name			= "iSCSI Initiator over TCP/IP",
@@ -1124,6 +1129,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_sw_tcp_netns,
 };
 
 static int __init iscsi_sw_tcp_init(void)
drivers/scsi/scsi_transport_iscsi.c +6 -1
index 230b43d34c5f..996a9abfa1f5 100644
@@ -1600,10 +1600,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 */
include/scsi/scsi_transport_iscsi.h +1 -0
index af0c5a15f316..f8885d0c37d8 100644
@@ -156,6 +156,7 @@ struct iscsi_transport {
 	int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess);
 	int (*get_host_stats) (struct Scsi_Host *shost, char *buf, int len);
 	u8 (*check_protection)(struct iscsi_task *task, sector_t *sector);
+	struct net *(*get_netns)(struct Scsi_Host *shost);
 };
 
 /*
Signature · 1 line
2.39.1
#25 lore raw

Re: [RFC PATCH 5/9] iscsi: set netns for iscsi_tcp hosts

Quoted 6 lines · Lee Duncan

From: Lee Duncan <[email protected]>

This lets iscsi_tcp operate in multiple namespaces. It uses current during session creation to find the net namespace, but it might be better to manage to pass it along from the iscsi netlink socket.

And indeed, I'd rather use the namespace from the iscsi netlink socket. If you use the namespace from session creation you'd better hope that this function is not called from a workqueue ...

Quoted 13 lines
---
  drivers/scsi/iscsi_tcp.c            | 7 +++++++
  drivers/scsi/scsi_transport_iscsi.c | 7 ++++++-
  include/scsi/scsi_transport_iscsi.h | 1 +
  3 files changed, 14 insertions(+), 1 deletion(-)
drivers/scsi/iscsi_tcp.c +0 -0
index 0454d94e8cf0..22e7a5c93627 100644

drivers/scsi/iscsi_tcp.c static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) · line 1076

Quoted 8 lines
drivers/scsi/iscsi_tcp.c +5 -0
@@ -1069,6 +1069,11 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
  	return 0;
  }
 
+static struct net *iscsi_sw_tcp_netns(struct Scsi_Host *shost)
+{
+	return current->nsproxy->net_ns;
+}
+

See above if you can't reference the namespace for the netlink socket here.

Quoted 38 lines
drivers/scsi/iscsi_tcp.c +2 -0
  static struct scsi_host_template iscsi_sw_tcp_sht = {
  	.module			= THIS_MODULE,
  	.name			= "iSCSI Initiator over TCP/IP",
@@ -1124,6 +1129,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_sw_tcp_netns,
  };
 
  static int __init iscsi_sw_tcp_init(void)
drivers/scsi/scsi_transport_iscsi.c +6 -1
index 230b43d34c5f..996a9abfa1f5 100644
@@ -1600,10 +1600,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 */
include/scsi/scsi_transport_iscsi.h +0 -0
index af0c5a15f316..f8885d0c37d8 100644

include/scsi/scsi_transport_iscsi.h struct iscsi_transport { · line 162

Quoted 7 lines
include/scsi/scsi_transport_iscsi.h +1 -0
@@ -156,6 +156,7 @@ struct iscsi_transport {
  	int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess);
  	int (*get_host_stats) (struct Scsi_Host *shost, char *buf, int len);
  	u8 (*check_protection)(struct iscsi_task *task, sector_t *sector);
+	struct net *(*get_netns)(struct Scsi_Host *shost);
  };
 
  /*

Cheers,

Hannes

maintainer
#26 lore raw

Re: [RFC PATCH 5/9] iscsi: set netns for iscsi_tcp hosts

Quoted 10 lines · Hannes Reinecke
Quoted 6 lines · Lee Duncan

From: Lee Duncan <[email protected]>

This lets iscsi_tcp operate in multiple namespaces. It uses current during session creation to find the net namespace, but it might be better to manage to pass it along from the iscsi netlink socket.

And indeed, I'd rather use the namespace from the iscsi netlink socket. If you use the namespace from session creation you'd better hope that this function is not called from a workqueue ...

The cleanest way I see to do this is to split the transport session_create function between bound and unbound, instead of checking for a NULL ep. That should cleanly serperate out the host-per-session behavior of iscsi_tcp, so we can pass in the namespace without changing the other drivers.

This is what that looks like on top of the existing patches, but we can merge it in and rearrange if desired.

- Chris

---

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.

---
 drivers/infiniband/ulp/iser/iscsi_iser.c | 41 +++++++++++++++++-------
 drivers/scsi/iscsi_tcp.c                 | 16 ++++-----
 drivers/scsi/iscsi_tcp.h                 |  1 +
 drivers/scsi/scsi_transport_iscsi.c      | 17 +++++++---
 include/scsi/scsi_transport_iscsi.h      |  3 ++
 5 files changed, 52 insertions(+), 26 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +29 -12
index 6865f62eb831..ca8de612d585 100644
@@ -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;
@@ -694,6 +684,32 @@ 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 supprot 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_unbound_session_create(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)
 {
@@ -983,6 +999,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_unbound_session = iscsi_iser_unbound_session_create,
 	.destroy_session        = iscsi_iser_session_destroy,
 	/* connection management */
 	.create_conn            = iscsi_iser_conn_create,
drivers/scsi/iscsi_tcp.c +7 -9
index 171685011ad9..b78239f25073 100644
@@ -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;
@@ -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)
@@ -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);
+	tcp_sw_host->net_ns = net;
+
 	if (iscsi_host_add(shost, NULL))
 		goto free_host;
 
@@ -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;
 
@@ -1074,7 +1071,8 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
 
 static struct net *iscsi_sw_tcp_netns(struct Scsi_Host *shost)
 {
-	return current->nsproxy->net_ns;
+	struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
+	return tcp_sw_host->net_ns;
 }
 
 static struct scsi_host_template iscsi_sw_tcp_sht = {
@@ -1104,7 +1102,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_unbound_session	= iscsi_sw_tcp_session_create,
 	.destroy_session	= iscsi_sw_tcp_session_destroy,
 	/* connection management */
 	.create_conn		= iscsi_sw_tcp_conn_create,
drivers/scsi/iscsi_tcp.h +1 -0
index 68e14a344904..f0020cb22f59 100644
@@ -53,6 +53,7 @@ struct iscsi_sw_tcp_conn {
 
 struct iscsi_sw_tcp_host {
 	struct iscsi_session	*session;
+	struct net *net_ns;
 };
 
 struct iscsi_sw_tcp_hdrbuf {
drivers/scsi/scsi_transport_iscsi.c +12 -5
index 8fafa8f0e0df..4d346e79468e 100644
@@ -3144,14 +3144,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_unbound_session(net, cmds_max,
+							    queue_depth,
+							    initial_cmdsn);
+	}
+
 	if (!session)
 		return -ENOMEM;
 
@@ -4145,7 +4152,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:
@@ -4160,7 +4167,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:
include/scsi/scsi_transport_iscsi.h +3 -0
index 0c3fd690ecf8..4d8a3d770bed 100644
@@ -79,6 +79,9 @@ struct iscsi_transport {
 	struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
 					uint16_t cmds_max, uint16_t qdepth,
 					uint32_t sn);
+	struct iscsi_cls_session *(*create_unbound_session) (struct net *net,
+					uint16_t cmds_max, uint16_t qdepth,
+					uint32_t sn);
 	void (*destroy_session) (struct iscsi_cls_session *session);
 	struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
 				uint32_t cid);
Signature · 1 line
2.39.2
#27 lore raw

Re: [RFC PATCH 5/9] iscsi: set netns for iscsi_tcp hosts

Quoted 238 lines · Chris Leech
Quoted 10 lines · Hannes Reinecke
Quoted 6 lines · Lee Duncan

From: Lee Duncan <[email protected]>

This lets iscsi_tcp operate in multiple namespaces. It uses current during session creation to find the net namespace, but it might be better to manage to pass it along from the iscsi netlink socket.

And indeed, I'd rather use the namespace from the iscsi netlink socket. If you use the namespace from session creation you'd better hope that this function is not called from a workqueue ...

The cleanest way I see to do this is to split the transport session_create function between bound and unbound, instead of checking for a NULL ep. That should cleanly serperate out the host-per-session behavior of iscsi_tcp, so we can pass in the namespace without changing the other drivers.

This is what that looks like on top of the existing patches, but we can merge it in and rearrange if desired.

- Chris

---

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.

---
  drivers/infiniband/ulp/iser/iscsi_iser.c | 41 +++++++++++++++++-------
  drivers/scsi/iscsi_tcp.c                 | 16 ++++-----
  drivers/scsi/iscsi_tcp.h                 |  1 +
  drivers/scsi/scsi_transport_iscsi.c      | 17 +++++++---
  include/scsi/scsi_transport_iscsi.h      |  3 ++
  5 files changed, 52 insertions(+), 26 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +29 -12
index 6865f62eb831..ca8de612d585 100644
@@ -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;
@@ -694,6 +684,32 @@ 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 supprot 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_unbound_session_create(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)
  {
@@ -983,6 +999,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_unbound_session = iscsi_iser_unbound_session_create,
  	.destroy_session        = iscsi_iser_session_destroy,
  	/* connection management */
  	.create_conn            = iscsi_iser_conn_create,
drivers/scsi/iscsi_tcp.c +7 -9
index 171685011ad9..b78239f25073 100644
@@ -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;
@@ -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)
@@ -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);
+	tcp_sw_host->net_ns = net;
+
  	if (iscsi_host_add(shost, NULL))
  		goto free_host;
 
@@ -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;
 
@@ -1074,7 +1071,8 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
 
  static struct net *iscsi_sw_tcp_netns(struct Scsi_Host *shost)
  {
-	return current->nsproxy->net_ns;
+	struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
+	return tcp_sw_host->net_ns;
  }
 
  static struct scsi_host_template iscsi_sw_tcp_sht = {
@@ -1104,7 +1102,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_unbound_session	= iscsi_sw_tcp_session_create,
  	.destroy_session	= iscsi_sw_tcp_session_destroy,
  	/* connection management */
  	.create_conn		= iscsi_sw_tcp_conn_create,
drivers/scsi/iscsi_tcp.h +1 -0
index 68e14a344904..f0020cb22f59 100644
@@ -53,6 +53,7 @@ struct iscsi_sw_tcp_conn {
 
  struct iscsi_sw_tcp_host {
  	struct iscsi_session	*session;
+	struct net *net_ns;
  };
 
  struct iscsi_sw_tcp_hdrbuf {
drivers/scsi/scsi_transport_iscsi.c +12 -5
index 8fafa8f0e0df..4d346e79468e 100644
@@ -3144,14 +3144,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_unbound_session(net, cmds_max,
+							    queue_depth,
+							    initial_cmdsn);
+	}
+
  	if (!session)
  		return -ENOMEM;
 
@@ -4145,7 +4152,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:
@@ -4160,7 +4167,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:
include/scsi/scsi_transport_iscsi.h +0 -0
index 0c3fd690ecf8..4d8a3d770bed 100644

include/scsi/scsi_transport_iscsi.h struct iscsi_transport { · line 87

Quoted 9 lines
include/scsi/scsi_transport_iscsi.h +3 -0
@@ -79,6 +79,9 @@ struct iscsi_transport {
  	struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
  					uint16_t cmds_max, uint16_t qdepth,
  					uint32_t sn);
+	struct iscsi_cls_session *(*create_unbound_session) (struct net *net,
+					uint16_t cmds_max, uint16_t qdepth,
+					uint32_t sn);
  	void (*destroy_session) (struct iscsi_cls_session *session);
  	struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
  				uint32_t cid);

I'm not _that_ happy with these two functions; but can't really see a way around it. Can't we rename the 'unbound' version to
'create_session_ns' or something?

Cheers,

Hannes

Signature · 5 lines
Dr. Hannes Reinecke                Kernel Storage Architect
[email protected]                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman
maintainer
#28 lore raw

Re: [RFC PATCH 5/9] iscsi: set netns for iscsi_tcp hosts

Quoted 12 lines · Hannes Reinecke
Quoted 11 lines · Chris Leech
include/scsi/scsi_transport_iscsi.h +3 -0
index 0c3fd690ecf8..4d8a3d770bed 100644
@@ -79,6 +79,9 @@ struct iscsi_transport {
  	struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
  					uint16_t cmds_max, uint16_t qdepth,
  					uint32_t sn);
+	struct iscsi_cls_session *(*create_unbound_session) (struct net *net,
+					uint16_t cmds_max, uint16_t qdepth,
+					uint32_t sn);
Quoted 8 lines

include/scsi/scsi_transport_iscsi.h struct iscsi_transport { · line 87

Quoted 3 lines
include/scsi/scsi_transport_iscsi.h +0 -0
  	void (*destroy_session) (struct iscsi_cls_session *session);
  	struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
  				uint32_t cid);

I'm not _that_ happy with these two functions; but can't really see a way around it.
Can't we rename the 'unbound' version to
'create_session_ns' or something?

Yes, in my mind I was matching the netlink commands, but those are create_session and create_bound_session. I got it exactly backwards with which one had the additional text.

I'm OK with changing to a shorter name, like the one you suggested.

Thanks,
- Chris

author
#29 lore raw

RFC PATCH 6/9 iscsi: check net namespace for all iscsi lookup

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

All internal lookups of iSCSI transport objects need to be filtered by net namespace.

---
 drivers/infiniband/ulp/iser/iscsi_iser.c |   5 +-
 drivers/scsi/be2iscsi/be_iscsi.c         |   4 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c         |   4 +-
 drivers/scsi/cxgbi/libcxgbi.c            |   4 +-
 drivers/scsi/qedi/qedi_iscsi.c           |   4 +-
 drivers/scsi/qla4xxx/ql4_os.c            |   8 +-
 drivers/scsi/scsi_transport_iscsi.c      | 202 ++++++++++++++---------
 include/scsi/scsi_transport_iscsi.h      |   5 +-
 8 files changed, 149 insertions(+), 87 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +4 -1
index d38c909b462f..348bafb55e51 100644
@@ -456,15 +456,18 @@ static int iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
 	struct iscsi_conn *conn = cls_conn->dd_data;
 	struct iser_conn *iser_conn;
 	struct iscsi_endpoint *ep;
+	struct net *net;
 	int error;
 
 	error = iscsi_conn_bind(cls_session, cls_conn, is_leading);
 	if (error)
 		return error;
 
+
 	/* the transport ep handle comes from user space so it must be
 	 * verified against the global ib connections list */
-	ep = iscsi_lookup_endpoint(transport_eph);
+	net = iscsi_sess_net(cls_session);
+	ep = iscsi_lookup_endpoint(net, transport_eph);
 	if (!ep) {
 		iser_err("can't bind eph %llx\n",
 			 (unsigned long long)transport_eph);
drivers/scsi/be2iscsi/be_iscsi.c +3 -1
index c893d193f5ef..10329ed6a9a8 100644
@@ -183,8 +183,10 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
 	struct iscsi_endpoint *ep;
 	uint16_t cri_index;
 	int rc = 0;
+	struct net *net;
 
-	ep = iscsi_lookup_endpoint(transport_fd);
+	net = iscsi_sess_net(cls_session);
+	ep = iscsi_lookup_endpoint(net, transport_fd);
 	if (!ep)
 		return -EINVAL;
 
drivers/scsi/bnx2i/bnx2i_iscsi.c +3 -1
index ac63e93e07c6..e889c5585c87 100644
@@ -1411,9 +1411,11 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
 	struct bnx2i_hba *hba = iscsi_host_priv(shost);
 	struct bnx2i_endpoint *bnx2i_ep;
 	struct iscsi_endpoint *ep;
+	struct net *net;
 	int ret_code;
 
-	ep = iscsi_lookup_endpoint(transport_fd);
+	net = iscsi_sess_net(cls_session);
+	ep = iscsi_lookup_endpoint(net, transport_fd);
 	if (!ep)
 		return -EINVAL;
 	/*
drivers/scsi/cxgbi/libcxgbi.c +3 -1
index 94edf8e1fb0c..b492b57dbb2a 100644
@@ -2676,9 +2676,11 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
 	struct iscsi_endpoint *ep;
 	struct cxgbi_endpoint *cep;
 	struct cxgbi_sock *csk;
+	struct net *net;
 	int err;
 
-	ep = iscsi_lookup_endpoint(transport_eph);
+	net = iscsi_sess_net(cls_session);
+	ep = iscsi_lookup_endpoint(net, transport_eph);
 	if (!ep)
 		return -EINVAL;
 
drivers/scsi/qedi/qedi_iscsi.c +3 -1
index 4baf1dbb8e92..fc3406e6f82c 100644
@@ -389,8 +389,10 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
 	struct qedi_endpoint *qedi_ep;
 	struct iscsi_endpoint *ep;
 	int rc = 0;
+	struct net *net;
 
-	ep = iscsi_lookup_endpoint(transport_fd);
+	net = iscsi_sess_net(cls_session);
+	ep = iscsi_lookup_endpoint(net, transport_fd);
 	if (!ep)
 		return -EINVAL;
 
drivers/scsi/qla4xxx/ql4_os.c +5 -3
index acebf9c92c04..390b89bdec8f 100644
@@ -3217,6 +3217,7 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
 	struct ddb_entry *ddb_entry;
 	struct scsi_qla_host *ha;
 	struct iscsi_session *sess;
+	struct net *net;
 
 	sess = cls_session->dd_data;
 	ddb_entry = sess->dd_data;
@@ -3225,11 +3226,12 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
 			  cls_session->sid, cls_conn->cid));
 
-	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
-		return -EINVAL;
-	ep = iscsi_lookup_endpoint(transport_fd);
+	net = iscsi_sess_net(cls_session);
+	ep = iscsi_lookup_endpoint(net, transport_fd);
 	if (!ep)
 		return -EINVAL;
+	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
+		return -EINVAL;
 	conn = cls_conn->dd_data;
 	qla_conn = conn->dd_data;
 	qla_conn->qla_ep = ep->dd_data;
drivers/scsi/scsi_transport_iscsi.c +124 -78

622 lines not on this page · raw message

include/scsi/scsi_transport_iscsi.h +4 -1
index f8885d0c37d8..9ac1bc133693 100644
@@ -291,6 +291,8 @@ struct iscsi_cls_session {
 #define iscsi_endpoint_to_shost(_ep) \
 	dev_to_shost(_ep->dev.parent)
 
+extern struct net *iscsi_sess_net(struct iscsi_cls_session *session);
+
 #define starget_to_session(_stgt) \
 	iscsi_dev_to_session(_stgt->dev.parent)
 
@@ -470,7 +472,8 @@ extern void iscsi_block_session(struct iscsi_cls_session *session);
 extern struct iscsi_endpoint *iscsi_create_endpoint(struct Scsi_Host *shost,
 						    int dd_size);
 extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
-extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
+extern struct iscsi_endpoint *iscsi_lookup_endpoint(struct net *net,
+						    u64 handle);
 extern void iscsi_put_endpoint(struct iscsi_endpoint *ep);
 extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
 extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost,
Signature · 1 line
2.39.1
Reviewed-by on v1 6/9
#30 lore raw

Re: [RFC PATCH 6/9] iscsi: check net namespace for all iscsi lookup

Quoted 7 lines · Lee Duncan

From: Lee Duncan <[email protected]>

All internal lookups of iSCSI transport objects need to be filtered by net namespace.

Quoted 11 lines
---
  drivers/infiniband/ulp/iser/iscsi_iser.c |   5 +-
  drivers/scsi/be2iscsi/be_iscsi.c         |   4 +-
  drivers/scsi/bnx2i/bnx2i_iscsi.c         |   4 +-
  drivers/scsi/cxgbi/libcxgbi.c            |   4 +-
  drivers/scsi/qedi/qedi_iscsi.c           |   4 +-
  drivers/scsi/qla4xxx/ql4_os.c            |   8 +-
  drivers/scsi/scsi_transport_iscsi.c      | 202 ++++++++++++++---------
  include/scsi/scsi_transport_iscsi.h      |   5 +-
  8 files changed, 149 insertions(+), 87 deletions(-)

Cheers,

Hannes

author
#31 lore raw

RFC PATCH 7/9 iscsi: convert flashnode devices from bus to class

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

The flashnode session and connection devices should be filtered by net namespace along with the iscsi_host, but we can't do that with a bus device. As these don't use any of the bus matching functionality, they make more sense as a class device anyway.

---
 drivers/scsi/qla4xxx/ql4_os.c       |  2 +-
 drivers/scsi/scsi_transport_iscsi.c | 36 ++++++++++++-----------------
 include/scsi/scsi_transport_iscsi.h |  2 ++
 3 files changed, 18 insertions(+), 22 deletions(-)
drivers/scsi/qla4xxx/ql4_os.c +1 -1
index 390b89bdec8f..18e382b6be18 100644
@@ -7185,7 +7185,7 @@ static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
 {
 	struct iscsi_bus_flash_session *fnode_sess;
 
-	if (!iscsi_flashnode_bus_match(dev, NULL))
+	if (!iscsi_is_flashnode_session_dev(dev))
 		return 0;
 
 	fnode_sess = iscsi_dev_to_flash_session(dev);
drivers/scsi/scsi_transport_iscsi.c +15 -21
index 008adde4dc51..c065763b1fc6 100644
@@ -1060,6 +1060,12 @@ static const struct device_type iscsi_flashnode_sess_dev_type = {
 	.release = iscsi_flashnode_sess_release,
 };
 
+bool iscsi_is_flashnode_session_dev(struct device *dev)
+{
+	return dev->type == &iscsi_flashnode_sess_dev_type;
+}
+EXPORT_SYMBOL_GPL(iscsi_is_flashnode_session_dev);
+
 /* flash node connection attrs show */
 #define iscsi_flashnode_conn_attr_show(type, name, param)		\
 static ssize_t								\
@@ -1246,20 +1252,8 @@ static const struct device_type iscsi_flashnode_conn_dev_type = {
 	.release = iscsi_flashnode_conn_release,
 };
 
-static struct bus_type iscsi_flashnode_bus;
-
-int iscsi_flashnode_bus_match(struct device *dev,
-				     struct device_driver *drv)
-{
-	if (dev->bus == &iscsi_flashnode_bus)
-		return 1;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_flashnode_bus_match);
-
-static struct bus_type iscsi_flashnode_bus = {
+static struct class iscsi_flashnode_bus = {
 	.name = "iscsi_flashnode",
-	.match = &iscsi_flashnode_bus_match,
 };
 
 /**
@@ -1290,7 +1284,7 @@ iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
 	fnode_sess->transport = transport;
 	fnode_sess->target_id = index;
 	fnode_sess->dev.type = &iscsi_flashnode_sess_dev_type;
-	fnode_sess->dev.bus = &iscsi_flashnode_bus;
+	fnode_sess->dev.class = &iscsi_flashnode_bus;
 	fnode_sess->dev.parent = &shost->shost_gendev;
 	dev_set_name(&fnode_sess->dev, "flashnode_sess-%u:%u",
 		     shost->host_no, index);
@@ -1338,7 +1332,7 @@ iscsi_create_flashnode_conn(struct Scsi_Host *shost,
 
 	fnode_conn->transport = transport;
 	fnode_conn->dev.type = &iscsi_flashnode_conn_dev_type;
-	fnode_conn->dev.bus = &iscsi_flashnode_bus;
+	fnode_conn->dev.class = &iscsi_flashnode_bus;
 	fnode_conn->dev.parent = &fnode_sess->dev;
 	dev_set_name(&fnode_conn->dev, "flashnode_conn-%u:%u:0",
 		     shost->host_no, fnode_sess->target_id);
@@ -1371,7 +1365,7 @@ EXPORT_SYMBOL_GPL(iscsi_create_flashnode_conn);
  */
 static int iscsi_is_flashnode_conn_dev(struct device *dev, void *data)
 {
-	return dev->bus == &iscsi_flashnode_bus;
+	return dev->type == &iscsi_flashnode_conn_dev_type;
 }
 
 static int iscsi_destroy_flashnode_conn(struct iscsi_bus_flash_conn *fnode_conn)
@@ -1385,7 +1379,7 @@ static int flashnode_match_index(struct device *dev, void *data)
 	struct iscsi_bus_flash_session *fnode_sess = NULL;
 	int ret = 0;
 
-	if (!iscsi_flashnode_bus_match(dev, NULL))
+	if (dev->type != &iscsi_flashnode_sess_dev_type)
 		goto exit_match_index;
 
 	fnode_sess = iscsi_dev_to_flash_session(dev);
@@ -1491,7 +1485,7 @@ EXPORT_SYMBOL_GPL(iscsi_destroy_flashnode_sess);
 
 static int iscsi_iter_destroy_flashnode_fn(struct device *dev, void *data)
 {
-	if (!iscsi_flashnode_bus_match(dev, NULL))
+	if (dev->type != &iscsi_flashnode_sess_dev_type)
 		return 0;
 
 	iscsi_destroy_flashnode_sess(iscsi_dev_to_flash_session(dev));
@@ -5200,7 +5194,7 @@ static __init int iscsi_transport_init(void)
 	if (err)
 		goto unregister_conn_class;
 
-	err = bus_register(&iscsi_flashnode_bus);
+	err = class_register(&iscsi_flashnode_bus);
 	if (err)
 		goto unregister_session_class;
 
@@ -5223,7 +5217,7 @@ static __init int iscsi_transport_init(void)
 unregister_pernet_subsys:
 	unregister_pernet_subsys(&iscsi_net_ops);
 unregister_flashnode_bus:
-	bus_unregister(&iscsi_flashnode_bus);
+	class_unregister(&iscsi_flashnode_bus);
 unregister_session_class:
 	transport_class_unregister(&iscsi_session_class);
 unregister_conn_class:
@@ -5243,7 +5237,7 @@ static void __exit iscsi_transport_exit(void)
 {
 	destroy_workqueue(iscsi_conn_cleanup_workq);
 	unregister_pernet_subsys(&iscsi_net_ops);
-	bus_unregister(&iscsi_flashnode_bus);
+	class_unregister(&iscsi_flashnode_bus);
 	transport_class_unregister(&iscsi_connection_class);
 	transport_class_unregister(&iscsi_session_class);
 	transport_class_unregister(&iscsi_host_class);
include/scsi/scsi_transport_iscsi.h +2 -0
index 9ac1bc133693..580f06d1479b 100644
@@ -512,6 +512,8 @@ iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
 extern struct device *
 iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess);
 
+extern bool iscsi_is_flashnode_session_dev(struct device *dev);
+
 extern char *
 iscsi_get_ipaddress_state_name(enum iscsi_ipaddress_state port_state);
 extern char *iscsi_get_router_state_name(enum iscsi_router_state router_state);
Signature · 1 line
2.39.1
Reviewed-by on v1 7/9
#32 lore raw

Re: [RFC PATCH 7/9] iscsi: convert flashnode devices from bus to class

Quoted 7 lines · Lee Duncan

From: Lee Duncan <[email protected]>

The flashnode session and connection devices should be filtered by net namespace along with the iscsi_host, but we can't do that with a bus device. As these don't use any of the bus matching functionality, they make more sense as a class device anyway.

Quoted 8 lines
---
  drivers/scsi/qla4xxx/ql4_os.c       |  2 +-
  drivers/scsi/scsi_transport_iscsi.c | 36 ++++++++++++-----------------
  include/scsi/scsi_transport_iscsi.h |  2 ++
  3 files changed, 18 insertions(+), 22 deletions(-)

Cheers,

Hannes

author
#33 lore raw

RFC PATCH 8/9 iscsi: rename iscsi_bus_flash_* to iscsi_flash_*

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

These are cleanups after the bus to class conversion for flashnode devices.

---
 drivers/scsi/qla4xxx/ql4_os.c       |  52 +++++++-------
 drivers/scsi/scsi_transport_iscsi.c | 102 ++++++++++++++--------------
 include/scsi/scsi_transport_iscsi.h |  48 ++++++-------
 3 files changed, 102 insertions(+), 100 deletions(-)
drivers/scsi/qla4xxx/ql4_os.c +26 -26
index 18e382b6be18..8af6847773e3 100644
@@ -168,20 +168,20 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
  * iSCSI Flash DDB sysfs entry points
  */
 static int
-qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
-			    struct iscsi_bus_flash_conn *fnode_conn,
+qla4xxx_sysfs_ddb_set_param(struct iscsi_flash_session *fnode_sess,
+			    struct iscsi_flash_conn *fnode_conn,
 			    void *data, int len);
 static int
-qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
+qla4xxx_sysfs_ddb_get_param(struct iscsi_flash_session *fnode_sess,
 			    int param, char *buf);
 static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
 				 int len);
 static int
-qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
-static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
-				   struct iscsi_bus_flash_conn *fnode_conn);
-static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
-				    struct iscsi_bus_flash_conn *fnode_conn);
+qla4xxx_sysfs_ddb_delete(struct iscsi_flash_session *fnode_sess);
+static int qla4xxx_sysfs_ddb_login(struct iscsi_flash_session *fnode_sess,
+				   struct iscsi_flash_conn *fnode_conn);
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_flash_session *fnode_sess,
+				    struct iscsi_flash_conn *fnode_conn);
 static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
 
 static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
@@ -3494,8 +3494,8 @@ static int qla4xxx_task_xmit(struct iscsi_task *task)
 	return -ENOSYS;
 }
 
-static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
-					 struct iscsi_bus_flash_conn *conn,
+static int qla4xxx_copy_from_fwddb_param(struct iscsi_flash_session *sess,
+					 struct iscsi_flash_conn *conn,
 					 struct dev_db_entry *fw_ddb_entry)
 {
 	unsigned long options = 0;
@@ -3636,8 +3636,8 @@ static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
 	return rc;
 }
 
-static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
-				       struct iscsi_bus_flash_conn *conn,
+static int qla4xxx_copy_to_fwddb_param(struct iscsi_flash_session *sess,
+				       struct iscsi_flash_conn *conn,
 				       struct dev_db_entry *fw_ddb_entry)
 {
 	uint16_t options;
@@ -7183,7 +7183,7 @@ static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
  **/
 static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
 {
-	struct iscsi_bus_flash_session *fnode_sess;
+	struct iscsi_flash_session *fnode_sess;
 
 	if (!iscsi_is_flashnode_session_dev(dev))
 		return 0;
@@ -7213,8 +7213,8 @@ static int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
 					struct dev_db_entry *fw_ddb_entry,
 					uint16_t *idx, int user)
 {
-	struct iscsi_bus_flash_session *fnode_sess = NULL;
-	struct iscsi_bus_flash_conn *fnode_conn = NULL;
+	struct iscsi_flash_session *fnode_sess = NULL;
+	struct iscsi_flash_conn *fnode_conn = NULL;
 	int rc = QLA_ERROR;
 
 	fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
@@ -7353,8 +7353,8 @@ static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
  * This writes the contents of target ddb buffer to Flash with a valid cookie
  * value in order to make the ddb entry persistent.
  **/
-static int  qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
-				    struct iscsi_bus_flash_conn *fnode_conn)
+static int  qla4xxx_sysfs_ddb_apply(struct iscsi_flash_session *fnode_sess,
+				    struct iscsi_flash_conn *fnode_conn)
 {
 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
 	struct scsi_qla_host *ha = to_qla_host(shost);
@@ -7543,8 +7543,8 @@ static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
  *
  * This logs in to the specified target
  **/
-static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
-				   struct iscsi_bus_flash_conn *fnode_conn)
+static int qla4xxx_sysfs_ddb_login(struct iscsi_flash_session *fnode_sess,
+				   struct iscsi_flash_conn *fnode_conn)
 {
 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
 	struct scsi_qla_host *ha = to_qla_host(shost);
@@ -7727,8 +7727,8 @@ static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
  *
  * This performs log out from the specified target
  **/
-static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
-				    struct iscsi_bus_flash_conn *fnode_conn)
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_flash_session *fnode_sess,
+				    struct iscsi_flash_conn *fnode_conn)
 {
 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
 	struct scsi_qla_host *ha = to_qla_host(shost);
@@ -7837,12 +7837,12 @@ static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
 }
 
 static int
-qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
+qla4xxx_sysfs_ddb_get_param(struct iscsi_flash_session *fnode_sess,
 			    int param, char *buf)
 {
 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
 	struct scsi_qla_host *ha = to_qla_host(shost);
-	struct iscsi_bus_flash_conn *fnode_conn;
+	struct iscsi_flash_conn *fnode_conn;
 	struct ql4_chap_table chap_tbl;
 	struct device *dev;
 	int parent_type;
@@ -8091,8 +8091,8 @@ qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
  * This sets the parameter of flash ddb entry and writes them to flash
  **/
 static int
-qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
-			    struct iscsi_bus_flash_conn *fnode_conn,
+qla4xxx_sysfs_ddb_set_param(struct iscsi_flash_session *fnode_sess,
+			    struct iscsi_flash_conn *fnode_conn,
 			    void *data, int len)
 {
 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
@@ -8319,7 +8319,7 @@ qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
  *
  * This invalidates the flash ddb entry at the given index
  **/
-static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
+static int qla4xxx_sysfs_ddb_delete(struct iscsi_flash_session *fnode_sess)
 {
 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
 	struct scsi_qla_host *ha = to_qla_host(shost);
drivers/scsi/scsi_transport_iscsi.c +51 -51

268 lines not on this page · raw message

include/scsi/scsi_transport_iscsi.h +25 -23

103 lines not on this page · raw message

Signature · 1 line
2.39.1
Reviewed-by on v1 8/9
#34 lore raw

Re: [RFC PATCH 8/9] iscsi: rename iscsi_bus_flash_* to iscsi_flash_*

Quoted 5 lines · Lee Duncan

From: Lee Duncan <[email protected]>

These are cleanups after the bus to class conversion for flashnode devices.

Quoted 8 lines
---
  drivers/scsi/qla4xxx/ql4_os.c       |  52 +++++++-------
  drivers/scsi/scsi_transport_iscsi.c | 102 ++++++++++++++--------------
  include/scsi/scsi_transport_iscsi.h |  48 ++++++-------
  3 files changed, 102 insertions(+), 100 deletions(-)

Can be merged with the previous patch, but otherwise:

Cheers,

Hannes

author
#35 lore raw

RFC PATCH 9/9 iscsi: filter flashnode sysfs by net namespace

In reply to Lee Duncan

From: Lee Duncan <[email protected]>

This finishes the net namespace support for flashnode sysfs devices.

---
 drivers/scsi/scsi_transport_iscsi.c | 34 +++++++++++++++++++++++++++++
 include/scsi/scsi_transport_iscsi.h |  4 ----
 2 files changed, 34 insertions(+), 4 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +34 -0
index 13393c025ccb..9a176ea0d866 100644
@@ -1268,8 +1268,42 @@ static int iscsi_is_flashnode_conn_dev(struct device *dev, void *data)
 	return dev->type == &iscsi_flashnode_conn_dev_type;
 }
 
+static struct net *iscsi_flashnode_sess_net(struct iscsi_flash_session *f_sess)
+{
+	struct Scsi_Host *shost = iscsi_flash_session_to_shost(f_sess);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+
+	return iscsi_host_net(ihost);
+}
+
+static struct net *iscsi_flashnode_conn_net(struct iscsi_flash_conn *f_conn)
+{
+	struct iscsi_flash_session *f_sess =
+		iscsi_flash_conn_to_flash_session(f_conn);
+
+	return iscsi_flashnode_sess_net(f_sess);
+}
+
+static const void *iscsi_flashnode_namespace(const struct device *dev)
+{
+	struct iscsi_flash_conn *f_conn;
+	struct iscsi_flash_session *f_sess;
+	struct device *dev_tmp = (struct device *)dev;
+
+	if (iscsi_is_flashnode_conn_dev(dev_tmp, NULL)) {
+		f_conn = iscsi_dev_to_flash_conn(dev);
+		return iscsi_flashnode_conn_net(f_conn);
+	} else if (iscsi_is_flashnode_session_dev(dev_tmp)) {
+		f_sess = iscsi_dev_to_flash_session(dev);
+		return iscsi_flashnode_sess_net(f_sess);
+	}
+	return NULL;
+}
+
 static struct class iscsi_flashnode = {
 	.name = "iscsi_flashnode",
+	.ns_type = &net_ns_type_operations,
+	.namespace = iscsi_flashnode_namespace,
 };
 
 /**
include/scsi/scsi_transport_iscsi.h +0 -4
index d03d9eb5707b..0c3fd690ecf8 100644
@@ -504,8 +504,6 @@ extern void
 iscsi_destroy_flashnode_sess(struct iscsi_flash_session *fnode_sess);
 
 extern void iscsi_destroy_all_flashnode(struct Scsi_Host *shost);
-extern int iscsi_flashnode_bus_match(struct device *dev,
-				     struct device_driver *drv);
 extern struct device *
 iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
 			  int (*fn)(struct device *dev, void *data));
@@ -514,8 +512,6 @@ iscsi_find_flashnode_conn(struct iscsi_flash_session *fnode_sess);
 
 extern bool iscsi_is_flashnode_session_dev(struct device *dev);
 
-extern bool iscsi_is_flashnode_session_dev(struct device *dev);
-
 extern char *
 iscsi_get_ipaddress_state_name(enum iscsi_ipaddress_state port_state);
 extern char *iscsi_get_router_state_name(enum iscsi_router_state router_state);
Signature · 1 line
2.39.1
Reviewed-by on v1 9/9
#36 lore raw

Re: [RFC PATCH 9/9] iscsi: filter flashnode sysfs by net namespace

Quoted 11 lines · Lee Duncan

From: Lee Duncan <[email protected]>

This finishes the net namespace support for flashnode sysfs devices.

---
  drivers/scsi/scsi_transport_iscsi.c | 34 +++++++++++++++++++++++++++++
  include/scsi/scsi_transport_iscsi.h |  4 ----
  2 files changed, 34 insertions(+), 4 deletions(-)

Cheers,

Hannes

maintainer
#37 lore raw

Re: [RFC 0/9] Make iscsid-kernel communications namespace-aware (resent)

In reply to Lee Duncan

[Resent to include all mailing lists]

I wanted to mention some issues I've discovered as part of testing this:

- Currently, only some sysfs entries are going to be different per namespace
- This means that the Configuration and Initiator Name are going to be common to all running daemons (this is /etc/iscsi)
- This also means that the Node database (and discovery DB, and interface DB) are common to all running daemons

I'm really not sure all running daemons should have the same initiator name. If we think of them as separate initiators, then this seems wrong.

Sharing the Node database may not be a good idea, either. This assumes that nodes discovered (and saved) from one namespace can actually be reached from other namespaces, but this may not be true. Having the Node DB and initiatorname shared means the different iscsid instances must cooperate with each other, else their requests can collide. Also, I can imagine situations where different daemons may want to set different configuration values. Currently they cannot.

Quoted 45 lines · Lee Duncan

From: Lee Duncan <[email protected]>

This is a request for comment on a set of patches that modify the kernel iSCSI initiator communications so that they are namespace-aware. The goal is to allow multiple iSCSI daemon (iscsid) to run at once as long as they are in separate namespaces, and so that iscsid can run in containers.

Comments and suggestions are more than welcome. I do not expect that this code is production-ready yet, and networking isn't my strongest suit (yet).

These patches were originally posted in 2015 by Chris Leech. There were some issues at the time about how to handle namespaces going away. I hope to address any issues raised with this patchset and then to merge these changes upstream to address working in working in containers.

My contribution thus far has been to update these patches to work with the current upstream kernel.

Chris Leech/Lee Duncan (9):
iscsi: create per-net iscsi netlink kernel sockets
iscsi: associate endpoints with a host
iscsi: sysfs filtering by network namespace
iscsi: make all iSCSI netlink multicast namespace aware
iscsi: set netns for iscsi_tcp hosts
iscsi: check net namespace for all iscsi lookup
iscsi: convert flashnode devices from bus to class
iscsi: rename iscsi_bus_flash_* to iscsi_flash_*
iscsi: filter flashnode sysfs by net namespace

  drivers/infiniband/ulp/iser/iscsi_iser.c |   7 +-
  drivers/scsi/be2iscsi/be_iscsi.c         |   6 +-
  drivers/scsi/bnx2i/bnx2i_iscsi.c         |   6 +-
  drivers/scsi/cxgbi/libcxgbi.c            |   6 +-
  drivers/scsi/iscsi_tcp.c                 |   7 +
  drivers/scsi/qedi/qedi_iscsi.c           |   6 +-
  drivers/scsi/qla4xxx/ql4_os.c            |  64 +--
  drivers/scsi/scsi_transport_iscsi.c      | 625 ++++++++++++++++-------
  include/scsi/scsi_transport_iscsi.h      |  63 ++-
  9 files changed, 537 insertions(+), 253 deletions(-)
#38 lore raw
In reply to Lee Duncan
Quoted 34 lines · Lee Duncan

From: Lee Duncan <[email protected]>

This is a request for comment on a set of patches that modify the kernel iSCSI initiator communications so that they are namespace-aware. The goal is to allow multiple iSCSI daemon (iscsid) to run at once as long as they are in separate namespaces, and so that iscsid can run in containers.

Comments and suggestions are more than welcome. I do not expect that this code is production-ready yet, and networking isn't my strongest suit (yet).

These patches were originally posted in 2015 by Chris Leech. There were some issues at the time about how to handle namespaces going away. I hope to address any issues raised with this patchset and then to merge these changes upstream to address working in working in containers.

My contribution thus far has been to update these patches to work with the current upstream kernel.

Chris Leech/Lee Duncan (9):
iscsi: create per-net iscsi netlink kernel sockets
iscsi: associate endpoints with a host
iscsi: sysfs filtering by network namespace
iscsi: make all iSCSI netlink multicast namespace aware
iscsi: set netns for iscsi_tcp hosts
iscsi: check net namespace for all iscsi lookup
iscsi: convert flashnode devices from bus to class
iscsi: rename iscsi_bus_flash_* to iscsi_flash_*
iscsi: filter flashnode sysfs by net namespace

Quoted 11 lines
  drivers/infiniband/ulp/iser/iscsi_iser.c |   7 +-
  drivers/scsi/be2iscsi/be_iscsi.c         |   6 +-
  drivers/scsi/bnx2i/bnx2i_iscsi.c         |   6 +-
  drivers/scsi/cxgbi/libcxgbi.c            |   6 +-
  drivers/scsi/iscsi_tcp.c                 |   7 +
  drivers/scsi/qedi/qedi_iscsi.c           |   6 +-
  drivers/scsi/qla4xxx/ql4_os.c            |  64 +--
  drivers/scsi/scsi_transport_iscsi.c      | 625 ++++++++++++++++-------
  include/scsi/scsi_transport_iscsi.h      |  63 ++-
  9 files changed, 537 insertions(+), 253 deletions(-)

Awesome work!

Thanks for this!

Comments to follow on the individual patches.

Cheers,

Hannes