tipc: name tipc name table support net namespace
[deliverable/linux.git] / net / tipc / name_table.c
index beed5fdda00451199b1fe120e5b4b2a733a29a1f..57e39c16a8c309030b3f4333909fe3a0040b2e1e 100644 (file)
@@ -34,6 +34,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <net/sock.h>
 #include "core.h"
 #include "config.h"
 #include "name_table.h"
@@ -106,9 +107,6 @@ struct name_seq {
        struct rcu_head rcu;
 };
 
-struct name_table *tipc_nametbl;
-DEFINE_SPINLOCK(tipc_nametbl_lock);
-
 static int hash(int x)
 {
        return x & (TIPC_NAMETBL_SIZE - 1);
@@ -448,12 +446,13 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq,
        }
 }
 
-static struct name_seq *nametbl_find_seq(u32 type)
+static struct name_seq *nametbl_find_seq(struct net *net, u32 type)
 {
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
        struct hlist_head *seq_head;
        struct name_seq *ns;
 
-       seq_head = &tipc_nametbl->seq_hlist[hash(type)];
+       seq_head = &tn->nametbl->seq_hlist[hash(type)];
        hlist_for_each_entry_rcu(ns, seq_head, ns_list) {
                if (ns->type == type)
                        return ns;
@@ -462,11 +461,13 @@ static struct name_seq *nametbl_find_seq(u32 type)
        return NULL;
 };
 
-struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
-                                            u32 scope, u32 node, u32 port, u32 key)
+struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
+                                            u32 lower, u32 upper, u32 scope,
+                                            u32 node, u32 port, u32 key)
 {
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
        struct publication *publ;
-       struct name_seq *seq = nametbl_find_seq(type);
+       struct name_seq *seq = nametbl_find_seq(net, type);
        int index = hash(type);
 
        if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) ||
@@ -477,8 +478,7 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
        }
 
        if (!seq)
-               seq = tipc_nameseq_create(type,
-                                         &tipc_nametbl->seq_hlist[index]);
+               seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
        if (!seq)
                return NULL;
 
@@ -489,11 +489,12 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
        return publ;
 }
 
-struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
-                                            u32 node, u32 ref, u32 key)
+struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
+                                            u32 lower, u32 node, u32 ref,
+                                            u32 key)
 {
        struct publication *publ;
-       struct name_seq *seq = nametbl_find_seq(type);
+       struct name_seq *seq = nametbl_find_seq(net, type);
 
        if (!seq)
                return NULL;
@@ -524,7 +525,8 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
  * - if name translation is attempted and fails, sets 'destnode' to 0
  *   and returns 0
  */
-u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
+u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance,
+                          u32 *destnode)
 {
        struct sub_seq *sseq;
        struct name_info *info;
@@ -537,7 +539,7 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
                return 0;
 
        rcu_read_lock();
-       seq = nametbl_find_seq(type);
+       seq = nametbl_find_seq(net, type);
        if (unlikely(!seq))
                goto not_found;
        spin_lock_bh(&seq->lock);
@@ -610,8 +612,8 @@ not_found:
  *
  * Returns non-zero if any off-node ports overlap
  */
-int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
-                             struct tipc_port_list *dports)
+int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
+                             u32 limit, struct tipc_port_list *dports)
 {
        struct name_seq *seq;
        struct sub_seq *sseq;
@@ -620,7 +622,7 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
        int res = 0;
 
        rcu_read_lock();
-       seq = nametbl_find_seq(type);
+       seq = nametbl_find_seq(net, type);
        if (!seq)
                goto exit;
 
@@ -657,24 +659,25 @@ struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
 {
        struct publication *publ;
        struct sk_buff *buf = NULL;
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
 
-       spin_lock_bh(&tipc_nametbl_lock);
-       if (tipc_nametbl->local_publ_count >= TIPC_MAX_PUBLICATIONS) {
+       spin_lock_bh(&tn->nametbl_lock);
+       if (tn->nametbl->local_publ_count >= TIPC_MAX_PUBLICATIONS) {
                pr_warn("Publication failed, local publication limit reached (%u)\n",
                        TIPC_MAX_PUBLICATIONS);
-               spin_unlock_bh(&tipc_nametbl_lock);
+               spin_unlock_bh(&tn->nametbl_lock);
                return NULL;
        }
 
-       publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
-                                  tipc_own_addr, port_ref, key);
+       publ = tipc_nametbl_insert_publ(net, type, lower, upper, scope,
+                                       tipc_own_addr, port_ref, key);
        if (likely(publ)) {
-               tipc_nametbl->local_publ_count++;
-               buf = tipc_named_publish(publ);
+               tn->nametbl->local_publ_count++;
+               buf = tipc_named_publish(net, publ);
                /* Any pending external events? */
                tipc_named_process_backlog(net);
        }
-       spin_unlock_bh(&tipc_nametbl_lock);
+       spin_unlock_bh(&tn->nametbl_lock);
 
        if (buf)
                named_cluster_distribute(net, buf);
@@ -689,11 +692,13 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
 {
        struct publication *publ;
        struct sk_buff *skb = NULL;
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
 
-       spin_lock_bh(&tipc_nametbl_lock);
-       publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
+       spin_lock_bh(&tn->nametbl_lock);
+       publ = tipc_nametbl_remove_publ(net, type, lower, tipc_own_addr,
+                                       ref, key);
        if (likely(publ)) {
-               tipc_nametbl->local_publ_count--;
+               tn->nametbl->local_publ_count--;
                skb = tipc_named_withdraw(publ);
                /* Any pending external events? */
                tipc_named_process_backlog(net);
@@ -704,7 +709,7 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
                       "(type=%u, lower=%u, ref=%u, key=%u)\n",
                       type, lower, ref, key);
        }
-       spin_unlock_bh(&tipc_nametbl_lock);
+       spin_unlock_bh(&tn->nametbl_lock);
 
        if (skb) {
                named_cluster_distribute(net, skb);
@@ -718,15 +723,15 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
  */
 void tipc_nametbl_subscribe(struct tipc_subscription *s)
 {
+       struct tipc_net *tn = net_generic(s->net, tipc_net_id);
        u32 type = s->seq.type;
        int index = hash(type);
        struct name_seq *seq;
 
-       spin_lock_bh(&tipc_nametbl_lock);
-       seq = nametbl_find_seq(type);
+       spin_lock_bh(&tn->nametbl_lock);
+       seq = nametbl_find_seq(s->net, type);
        if (!seq)
-               seq = tipc_nameseq_create(type,
-                                         &tipc_nametbl->seq_hlist[index]);
+               seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
        if (seq) {
                spin_lock_bh(&seq->lock);
                tipc_nameseq_subscribe(seq, s);
@@ -735,7 +740,7 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s)
                pr_warn("Failed to create subscription for {%u,%u,%u}\n",
                        s->seq.type, s->seq.lower, s->seq.upper);
        }
-       spin_unlock_bh(&tipc_nametbl_lock);
+       spin_unlock_bh(&tn->nametbl_lock);
 }
 
 /**
@@ -743,10 +748,11 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s)
  */
 void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
 {
+       struct tipc_net *tn = net_generic(s->net, tipc_net_id);
        struct name_seq *seq;
 
-       spin_lock_bh(&tipc_nametbl_lock);
-       seq = nametbl_find_seq(s->seq.type);
+       spin_lock_bh(&tn->nametbl_lock);
+       seq = nametbl_find_seq(s->net, s->seq.type);
        if (seq != NULL) {
                spin_lock_bh(&seq->lock);
                list_del_init(&s->nameseq_list);
@@ -759,7 +765,7 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
                        spin_unlock_bh(&seq->lock);
                }
        }
-       spin_unlock_bh(&tipc_nametbl_lock);
+       spin_unlock_bh(&tn->nametbl_lock);
 }
 
 /**
@@ -861,9 +867,10 @@ static int nametbl_header(char *buf, int len, u32 depth)
 /**
  * nametbl_list - print specified name table contents into the given buffer
  */
-static int nametbl_list(char *buf, int len, u32 depth_info,
+static int nametbl_list(struct net *net, char *buf, int len, u32 depth_info,
                        u32 type, u32 lowbound, u32 upbound)
 {
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
        struct hlist_head *seq_head;
        struct name_seq *seq;
        int all_types;
@@ -883,7 +890,7 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
                lowbound = 0;
                upbound = ~0;
                for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
-                       seq_head = &tipc_nametbl->seq_hlist[i];
+                       seq_head = &tn->nametbl->seq_hlist[i];
                        hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
                                ret += nameseq_list(seq, buf + ret, len - ret,
                                                   depth, seq->type,
@@ -899,7 +906,7 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
                }
                ret += nametbl_header(buf + ret, len - ret, depth);
                i = hash(type);
-               seq_head = &tipc_nametbl->seq_hlist[i];
+               seq_head = &tn->nametbl->seq_hlist[i];
                hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
                        if (seq->type == type) {
                                ret += nameseq_list(seq, buf + ret, len - ret,
@@ -912,7 +919,8 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
        return ret;
 }
 
-struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_nametbl_get(struct net *net, const void *req_tlv_area,
+                                int req_tlv_space)
 {
        struct sk_buff *buf;
        struct tipc_name_table_query *argv;
@@ -933,7 +941,7 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
        pb_len = ULTRA_STRING_MAX_LEN;
        argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
        rcu_read_lock();
-       str_len = nametbl_list(pb, pb_len, ntohl(argv->depth),
+       str_len = nametbl_list(net, pb, pb_len, ntohl(argv->depth),
                               ntohl(argv->type),
                               ntohl(argv->lowbound), ntohl(argv->upbound));
        rcu_read_unlock();
@@ -944,8 +952,10 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
        return buf;
 }
 
-int tipc_nametbl_init(void)
+int tipc_nametbl_init(struct net *net)
 {
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
+       struct name_table *tipc_nametbl;
        int i;
 
        tipc_nametbl = kzalloc(sizeof(*tipc_nametbl), GFP_ATOMIC);
@@ -958,6 +968,8 @@ int tipc_nametbl_init(void)
        INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_ZONE_SCOPE]);
        INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_CLUSTER_SCOPE]);
        INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_NODE_SCOPE]);
+       tn->nametbl = tipc_nametbl;
+       spin_lock_init(&tn->nametbl_lock);
        return 0;
 }
 
@@ -966,7 +978,7 @@ int tipc_nametbl_init(void)
  *
  * tipc_nametbl_lock must be held when calling this function
  */
-static void tipc_purge_publications(struct name_seq *seq)
+static void tipc_purge_publications(struct net *net, struct name_seq *seq)
 {
        struct publication *publ, *safe;
        struct sub_seq *sseq;
@@ -976,8 +988,8 @@ static void tipc_purge_publications(struct name_seq *seq)
        sseq = seq->sseqs;
        info = sseq->info;
        list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
-               tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
-                                        publ->ref, publ->key);
+               tipc_nametbl_remove_publ(net, publ->type, publ->lower,
+                                        publ->node, publ->ref, publ->key);
                kfree_rcu(publ, rcu);
        }
        hlist_del_init_rcu(&seq->ns_list);
@@ -987,25 +999,27 @@ static void tipc_purge_publications(struct name_seq *seq)
        kfree_rcu(seq, rcu);
 }
 
-void tipc_nametbl_stop(void)
+void tipc_nametbl_stop(struct net *net)
 {
        u32 i;
        struct name_seq *seq;
        struct hlist_head *seq_head;
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
+       struct name_table *tipc_nametbl = tn->nametbl;
 
        /* Verify name table is empty and purge any lingering
         * publications, then release the name table
         */
-       spin_lock_bh(&tipc_nametbl_lock);
+       spin_lock_bh(&tn->nametbl_lock);
        for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
                if (hlist_empty(&tipc_nametbl->seq_hlist[i]))
                        continue;
                seq_head = &tipc_nametbl->seq_hlist[i];
                hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
-                       tipc_purge_publications(seq);
+                       tipc_purge_publications(net, seq);
                }
        }
-       spin_unlock_bh(&tipc_nametbl_lock);
+       spin_unlock_bh(&tn->nametbl_lock);
 
        synchronize_net();
        kfree(tipc_nametbl);
@@ -1109,9 +1123,10 @@ static int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq,
        return 0;
 }
 
-static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type,
-                             u32 *last_lower, u32 *last_publ)
+static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg,
+                           u32 *last_type, u32 *last_lower, u32 *last_publ)
 {
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
        struct hlist_head *seq_head;
        struct name_seq *seq = NULL;
        int err;
@@ -1123,10 +1138,10 @@ static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type,
                i = 0;
 
        for (; i < TIPC_NAMETBL_SIZE; i++) {
-               seq_head = &tipc_nametbl->seq_hlist[i];
+               seq_head = &tn->nametbl->seq_hlist[i];
 
                if (*last_type) {
-                       seq = nametbl_find_seq(*last_type);
+                       seq = nametbl_find_seq(net, *last_type);
                        if (!seq)
                                return -EPIPE;
                } else {
@@ -1160,6 +1175,7 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
        u32 last_type = cb->args[0];
        u32 last_lower = cb->args[1];
        u32 last_publ = cb->args[2];
+       struct net *net = sock_net(skb->sk);
        struct tipc_nl_msg msg;
 
        if (done)
@@ -1170,7 +1186,7 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
        msg.seq = cb->nlh->nlmsg_seq;
 
        rcu_read_lock();
-       err = __tipc_nl_seq_list(&msg, &last_type, &last_lower, &last_publ);
+       err = tipc_nl_seq_list(net, &msg, &last_type, &last_lower, &last_publ);
        if (!err) {
                done = 1;
        } else if (err != -EMSGSIZE) {
This page took 0.046561 seconds and 5 git commands to generate.