From: Shachar Raindel <raindel@mellanox.com>
To: roland@kernel.org, sean.hefty@intel.com
Cc: linux-rdma@vger.kernel.org, netdev@vger.kernel.org,
liranl@mellanox.com, guysh@mellanox.com, haggaie@mellanox.com,
yotamke@mellanox.com, raindel@mellanox.com
Subject: [PATCH v1 07/10] IB/cma: Separate port allocation to network namespaces
Date: Wed, 11 Feb 2015 17:06:41 +0200 [thread overview]
Message-ID: <1423667204-8807-8-git-send-email-raindel@mellanox.com> (raw)
In-Reply-To: <1423667204-8807-1-git-send-email-raindel@mellanox.com>
From: Yotam Kenneth <yotamke@mellanox.com>
Keep a radix-tree for the network namespaces we support for each port-space.
Dynamically allocate idr for network namespace upon first bind request for a
port in the (ps, net) tuple.
Destroy the idr when the (ps, net) tuple does not contain any bounded ports.
This patch is internal infrastructure work for the following patch. In
this patch, init_net is statically used as the network namespace for
the new port-space API.
The radix-tree is protected under the same locking that protects the
rest of the port space data. This locking is practically a big, static
mutex lock for the entire module.
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Yotam Kenneth <yotamke@mellanox.com>
Signed-off-by: Shachar Raindel <raindel@mellanox.com>
Signed-off-by: Guy Shapiro <guysh@mellanox.com>
---
drivers/infiniband/core/cma.c | 122 ++++++++++++++++++++++++++++++++++--------
1 file changed, 99 insertions(+), 23 deletions(-)
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 1ce84a0..022b0d0 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -39,11 +39,13 @@
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/idr.h>
+#include <linux/radix-tree.h>
#include <linux/inetdevice.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <net/route.h>
+#include <net/netns/hash.h>
#include <net/tcp.h>
#include <net/ipv6.h>
@@ -80,10 +82,83 @@ static LIST_HEAD(dev_list);
static LIST_HEAD(listen_any_list);
static DEFINE_MUTEX(lock);
static struct workqueue_struct *cma_wq;
-static DEFINE_IDR(tcp_ps);
-static DEFINE_IDR(udp_ps);
-static DEFINE_IDR(ipoib_ps);
-static DEFINE_IDR(ib_ps);
+static RADIX_TREE(tcp_ps, GFP_KERNEL);
+static RADIX_TREE(udp_ps, GFP_KERNEL);
+static RADIX_TREE(ipoib_ps, GFP_KERNEL);
+static RADIX_TREE(ib_ps, GFP_KERNEL);
+
+static LIST_HEAD(idrs_list);
+
+struct idr_ll {
+ unsigned net_val;
+ struct net *net;
+ struct radix_tree_root *ps;
+ struct idr idr;
+};
+
+static void zap_ps_idr(struct idr_ll *idr_ll)
+{
+ radix_tree_delete(idr_ll->ps, idr_ll->net_val);
+ idr_destroy(&idr_ll->idr);
+ kfree(idr_ll);
+}
+
+static int cma_ps_alloc(struct radix_tree_root *ps, struct net *net, void *ptr,
+ int snum)
+{
+ struct idr_ll *idr_ll;
+ int err;
+ int res;
+
+ idr_ll = radix_tree_lookup(ps, net_hash_mix(net));
+ if (!idr_ll) {
+ idr_ll = kmalloc(sizeof(*idr_ll), GFP_KERNEL);
+ if (!idr_ll)
+ return -ENOMEM;
+ idr_init(&idr_ll->idr);
+ idr_ll->net_val = net_hash_mix(net);
+ idr_ll->net = net;
+ idr_ll->ps = ps;
+ err = radix_tree_insert(ps, idr_ll->net_val, idr_ll);
+ if (err) {
+ idr_destroy(&idr_ll->idr);
+ kfree(idr_ll);
+ return err;
+ }
+ }
+ res = idr_alloc(&idr_ll->idr, ptr, snum, snum + 1, GFP_KERNEL);
+ if (unlikely((res < 0) && idr_is_empty(&idr_ll->idr))) {
+ zap_ps_idr(idr_ll);
+ return res;
+ }
+ return res;
+}
+
+static void *cma_ps_find(struct radix_tree_root *ps, struct net *net, int snum)
+{
+ struct idr_ll *idr_ll;
+
+ idr_ll = radix_tree_lookup(ps, net_hash_mix(net));
+ if (!idr_ll)
+ return NULL;
+ return idr_find(&idr_ll->idr, snum);
+}
+
+static void cma_ps_remove(struct radix_tree_root *ps, struct net *net, int snum)
+{
+ struct idr_ll *idr_ll;
+
+ idr_ll = radix_tree_lookup(ps, net_hash_mix(net));
+ if (unlikely(!idr_ll)) {
+ WARN(1, "cma_ps_removed can't find expected net ns 0x%lx\n",
+ (unsigned long)net);
+ return;
+ }
+ idr_remove(&idr_ll->idr, snum);
+ if (idr_is_empty(&idr_ll->idr)) {
+ zap_ps_idr(idr_ll);
+ }
+}
struct cma_device {
struct list_head list;
@@ -94,9 +169,9 @@ struct cma_device {
};
struct rdma_bind_list {
- struct idr *ps;
- struct hlist_head owners;
- unsigned short port;
+ struct radix_tree_root *ps;
+ struct hlist_head owners;
+ unsigned short port;
};
enum {
@@ -885,7 +960,7 @@ static void cma_release_port(struct rdma_id_private *id_priv)
mutex_lock(&lock);
hlist_del(&id_priv->node);
if (hlist_empty(&bind_list->owners)) {
- idr_remove(bind_list->ps, bind_list->port);
+ cma_ps_remove(bind_list->ps, &init_net, bind_list->port);
kfree(bind_list);
}
mutex_unlock(&lock);
@@ -2198,8 +2273,8 @@ static void cma_bind_port(struct rdma_bind_list *bind_list,
hlist_add_head(&id_priv->node, &bind_list->owners);
}
-static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
- unsigned short snum)
+static int cma_alloc_port(struct radix_tree_root *ps,
+ struct rdma_id_private *id_priv, unsigned short snum)
{
struct rdma_bind_list *bind_list;
int ret;
@@ -2208,7 +2283,7 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
if (!bind_list)
return -ENOMEM;
- ret = idr_alloc(ps, bind_list, snum, snum + 1, GFP_KERNEL);
+ ret = cma_ps_alloc(ps, &init_net, bind_list, snum);
if (ret < 0)
goto err;
@@ -2221,7 +2296,8 @@ err:
return ret == -ENOSPC ? -EADDRNOTAVAIL : ret;
}
-static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
+static int cma_alloc_any_port(struct radix_tree_root *ps,
+ struct rdma_id_private *id_priv)
{
static unsigned int last_used_port;
int low, high, remaining;
@@ -2232,7 +2308,7 @@ static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
rover = prandom_u32() % remaining + low;
retry:
if (last_used_port != rover &&
- !idr_find(ps, (unsigned short) rover)) {
+ !cma_ps_find(ps, &init_net, (unsigned short)rover)) {
int ret = cma_alloc_port(ps, id_priv, rover);
/*
* Remember previously used port number in order to avoid
@@ -2257,6 +2333,8 @@ retry:
* bind to a specific port, or when trying to listen on a bound port. In
* the latter case, the provided id_priv may already be on the bind_list, but
* we still need to check that it's okay to start listening.
+ *
+ * Assume the bind_list contains only services from the correct name space.
*/
static int cma_check_port(struct rdma_bind_list *bind_list,
struct rdma_id_private *id_priv, uint8_t reuseaddr)
@@ -2287,7 +2365,8 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
return 0;
}
-static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
+static int cma_use_port(struct radix_tree_root *ps,
+ struct rdma_id_private *id_priv)
{
struct rdma_bind_list *bind_list;
unsigned short snum;
@@ -2297,7 +2376,7 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
- bind_list = idr_find(ps, snum);
+ bind_list = cma_ps_find(ps, &init_net, snum);
if (!bind_list) {
ret = cma_alloc_port(ps, id_priv, snum);
} else {
@@ -2320,7 +2399,8 @@ static int cma_bind_listen(struct rdma_id_private *id_priv)
return ret;
}
-static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv)
+static struct radix_tree_root *cma_select_inet_ps(
+ struct rdma_id_private *id_priv)
{
switch (id_priv->id.ps) {
case RDMA_PS_TCP:
@@ -2336,9 +2416,9 @@ static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv)
}
}
-static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv)
+static struct radix_tree_root *cma_select_ib_ps(struct rdma_id_private *id_priv)
{
- struct idr *ps = NULL;
+ struct radix_tree_root *ps = NULL;
struct sockaddr_ib *sib;
u64 sid_ps, mask, sid;
@@ -2369,7 +2449,7 @@ static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv)
static int cma_get_port(struct rdma_id_private *id_priv)
{
- struct idr *ps;
+ struct radix_tree_root *ps;
int ret;
if (cma_family(id_priv) != AF_IB)
@@ -3567,10 +3647,6 @@ static void __exit cma_cleanup(void)
rdma_addr_unregister_client(&addr_client);
ib_sa_unregister_client(&sa_client);
destroy_workqueue(cma_wq);
- idr_destroy(&tcp_ps);
- idr_destroy(&udp_ps);
- idr_destroy(&ipoib_ps);
- idr_destroy(&ib_ps);
}
module_init(cma_init);
--
1.7.11.2
next prev parent reply other threads:[~2015-02-11 15:11 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-02-11 15:06 [PATCH v1 00/10] Add network namespace support in the RDMA-CM Shachar Raindel
2015-02-11 15:06 ` [PATCH v1 01/10] IB/addr: Pass network namespace as a parameter Shachar Raindel
2015-02-11 15:06 ` [PATCH v1 02/10] IB/core: Pass network namespace as a parameter to relevant functions Shachar Raindel
2015-02-11 15:06 ` [PATCH v1 04/10] IB/ipoib: Return IPoIB devices as possible matches to get_net_device_by_port_pkey_ip Shachar Raindel
2015-02-11 15:06 ` [PATCH v1 05/10] IB/cm,cma: Move RDMA IP CM private-data parsing code from ib_cma to ib_cm Shachar Raindel
2015-02-11 15:06 ` [PATCH v1 06/10] IB/cm: Add network namespace support Shachar Raindel
2015-02-11 15:06 ` Shachar Raindel [this message]
2015-02-11 15:06 ` [PATCH v1 08/10] IB/cma: Add support for network namespaces Shachar Raindel
[not found] ` <1423667204-8807-1-git-send-email-raindel-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2015-02-11 15:06 ` [PATCH v1 03/10] IB/core: Find the network namespace matching connection parameters Shachar Raindel
2015-02-11 15:06 ` [PATCH v1 09/10] IB/ucma: Take the network namespace from the process Shachar Raindel
2015-02-16 8:10 ` [PATCH v1 00/10] Add network namespace support in the RDMA-CM Shachar Raindel
2015-02-11 15:06 ` [PATCH v1 10/10] IB/ucm: Add partial support for network namespaces Shachar Raindel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1423667204-8807-8-git-send-email-raindel@mellanox.com \
--to=raindel@mellanox.com \
--cc=guysh@mellanox.com \
--cc=haggaie@mellanox.com \
--cc=linux-rdma@vger.kernel.org \
--cc=liranl@mellanox.com \
--cc=netdev@vger.kernel.org \
--cc=roland@kernel.org \
--cc=sean.hefty@intel.com \
--cc=yotamke@mellanox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox