aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/tipc/bcast.c5
-rw-r--r--net/tipc/discover.c1
-rw-r--r--net/tipc/link.c7
-rw-r--r--net/tipc/name_distr.c2
-rw-r--r--net/tipc/node.c85
-rw-r--r--net/tipc/node.h9
6 files changed, 79 insertions, 30 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 4289dd62f589..ae558dd7f8ee 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -329,13 +329,12 @@ static void bclink_peek_nack(struct net *net, struct tipc_msg *msg)
329 return; 329 return;
330 330
331 tipc_node_lock(n_ptr); 331 tipc_node_lock(n_ptr);
332
333 if (n_ptr->bclink.recv_permitted && 332 if (n_ptr->bclink.recv_permitted &&
334 (n_ptr->bclink.last_in != n_ptr->bclink.last_sent) && 333 (n_ptr->bclink.last_in != n_ptr->bclink.last_sent) &&
335 (n_ptr->bclink.last_in == msg_bcgap_after(msg))) 334 (n_ptr->bclink.last_in == msg_bcgap_after(msg)))
336 n_ptr->bclink.oos_state = 2; 335 n_ptr->bclink.oos_state = 2;
337
338 tipc_node_unlock(n_ptr); 336 tipc_node_unlock(n_ptr);
337 tipc_node_put(n_ptr);
339} 338}
340 339
341/* tipc_bclink_xmit - deliver buffer chain to all nodes in cluster 340/* tipc_bclink_xmit - deliver buffer chain to all nodes in cluster
@@ -466,6 +465,7 @@ void tipc_bclink_rcv(struct net *net, struct sk_buff *buf)
466 tipc_node_unlock(node); 465 tipc_node_unlock(node);
467 bclink_peek_nack(net, msg); 466 bclink_peek_nack(net, msg);
468 } 467 }
468 tipc_node_put(node);
469 goto exit; 469 goto exit;
470 } 470 }
471 471
@@ -570,6 +570,7 @@ receive:
570 570
571unlock: 571unlock:
572 tipc_node_unlock(node); 572 tipc_node_unlock(node);
573 tipc_node_put(node);
573exit: 574exit:
574 kfree_skb(buf); 575 kfree_skb(buf);
575} 576}
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 169f3dd038b9..967e292f53c8 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -260,6 +260,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
260 } 260 }
261 } 261 }
262 tipc_node_unlock(node); 262 tipc_node_unlock(node);
263 tipc_node_put(node);
263} 264}
264 265
265/** 266/**
diff --git a/net/tipc/link.c b/net/tipc/link.c
index f5e086c5f724..514466efc25c 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -854,6 +854,7 @@ int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
854 if (link) 854 if (link)
855 rc = __tipc_link_xmit(net, link, list); 855 rc = __tipc_link_xmit(net, link, list);
856 tipc_node_unlock(node); 856 tipc_node_unlock(node);
857 tipc_node_put(node);
857 } 858 }
858 if (link) 859 if (link)
859 return rc; 860 return rc;
@@ -1116,8 +1117,8 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)
1116 n_ptr = tipc_node_find(net, msg_prevnode(msg)); 1117 n_ptr = tipc_node_find(net, msg_prevnode(msg));
1117 if (unlikely(!n_ptr)) 1118 if (unlikely(!n_ptr))
1118 goto discard; 1119 goto discard;
1119 tipc_node_lock(n_ptr);
1120 1120
1121 tipc_node_lock(n_ptr);
1121 /* Locate unicast link endpoint that should handle message */ 1122 /* Locate unicast link endpoint that should handle message */
1122 l_ptr = n_ptr->links[b_ptr->identity]; 1123 l_ptr = n_ptr->links[b_ptr->identity];
1123 if (unlikely(!l_ptr)) 1124 if (unlikely(!l_ptr))
@@ -1205,6 +1206,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)
1205 skb = NULL; 1206 skb = NULL;
1206unlock: 1207unlock:
1207 tipc_node_unlock(n_ptr); 1208 tipc_node_unlock(n_ptr);
1209 tipc_node_put(n_ptr);
1208discard: 1210discard:
1209 if (unlikely(skb)) 1211 if (unlikely(skb))
1210 kfree_skb(skb); 1212 kfree_skb(skb);
@@ -2236,7 +2238,6 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
2236 msg.seq = cb->nlh->nlmsg_seq; 2238 msg.seq = cb->nlh->nlmsg_seq;
2237 2239
2238 rcu_read_lock(); 2240 rcu_read_lock();
2239
2240 if (prev_node) { 2241 if (prev_node) {
2241 node = tipc_node_find(net, prev_node); 2242 node = tipc_node_find(net, prev_node);
2242 if (!node) { 2243 if (!node) {
@@ -2249,6 +2250,7 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
2249 cb->prev_seq = 1; 2250 cb->prev_seq = 1;
2250 goto out; 2251 goto out;
2251 } 2252 }
2253 tipc_node_put(node);
2252 2254
2253 list_for_each_entry_continue_rcu(node, &tn->node_list, 2255 list_for_each_entry_continue_rcu(node, &tn->node_list,
2254 list) { 2256 list) {
@@ -2256,6 +2258,7 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
2256 err = __tipc_nl_add_node_links(net, &msg, node, 2258 err = __tipc_nl_add_node_links(net, &msg, node,
2257 &prev_link); 2259 &prev_link);
2258 tipc_node_unlock(node); 2260 tipc_node_unlock(node);
2261 tipc_node_put(node);
2259 if (err) 2262 if (err)
2260 goto out; 2263 goto out;
2261 2264
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 506aaa565da7..41e7b7e4dda0 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -244,6 +244,7 @@ static void tipc_publ_subscribe(struct net *net, struct publication *publ,
244 tipc_node_lock(node); 244 tipc_node_lock(node);
245 list_add_tail(&publ->nodesub_list, &node->publ_list); 245 list_add_tail(&publ->nodesub_list, &node->publ_list);
246 tipc_node_unlock(node); 246 tipc_node_unlock(node);
247 tipc_node_put(node);
247} 248}
248 249
249static void tipc_publ_unsubscribe(struct net *net, struct publication *publ, 250static void tipc_publ_unsubscribe(struct net *net, struct publication *publ,
@@ -258,6 +259,7 @@ static void tipc_publ_unsubscribe(struct net *net, struct publication *publ,
258 tipc_node_lock(node); 259 tipc_node_lock(node);
259 list_del_init(&publ->nodesub_list); 260 list_del_init(&publ->nodesub_list);
260 tipc_node_unlock(node); 261 tipc_node_unlock(node);
262 tipc_node_put(node);
261} 263}
262 264
263/** 265/**
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 5cc43d34ad0a..3e4f04897c03 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -42,6 +42,7 @@
42 42
43static void node_lost_contact(struct tipc_node *n_ptr); 43static void node_lost_contact(struct tipc_node *n_ptr);
44static void node_established_contact(struct tipc_node *n_ptr); 44static void node_established_contact(struct tipc_node *n_ptr);
45static void tipc_node_delete(struct tipc_node *node);
45 46
46struct tipc_sock_conn { 47struct tipc_sock_conn {
47 u32 port; 48 u32 port;
@@ -67,6 +68,23 @@ static unsigned int tipc_hashfn(u32 addr)
67 return addr & (NODE_HTABLE_SIZE - 1); 68 return addr & (NODE_HTABLE_SIZE - 1);
68} 69}
69 70
71static void tipc_node_kref_release(struct kref *kref)
72{
73 struct tipc_node *node = container_of(kref, struct tipc_node, kref);
74
75 tipc_node_delete(node);
76}
77
78void tipc_node_put(struct tipc_node *node)
79{
80 kref_put(&node->kref, tipc_node_kref_release);
81}
82
83static void tipc_node_get(struct tipc_node *node)
84{
85 kref_get(&node->kref);
86}
87
70/* 88/*
71 * tipc_node_find - locate specified node object, if it exists 89 * tipc_node_find - locate specified node object, if it exists
72 */ 90 */
@@ -82,6 +100,7 @@ struct tipc_node *tipc_node_find(struct net *net, u32 addr)
82 hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)], 100 hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)],
83 hash) { 101 hash) {
84 if (node->addr == addr) { 102 if (node->addr == addr) {
103 tipc_node_get(node);
85 rcu_read_unlock(); 104 rcu_read_unlock();
86 return node; 105 return node;
87 } 106 }
@@ -106,6 +125,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
106 } 125 }
107 n_ptr->addr = addr; 126 n_ptr->addr = addr;
108 n_ptr->net = net; 127 n_ptr->net = net;
128 kref_init(&n_ptr->kref);
109 spin_lock_init(&n_ptr->lock); 129 spin_lock_init(&n_ptr->lock);
110 INIT_HLIST_NODE(&n_ptr->hash); 130 INIT_HLIST_NODE(&n_ptr->hash);
111 INIT_LIST_HEAD(&n_ptr->list); 131 INIT_LIST_HEAD(&n_ptr->list);
@@ -120,16 +140,17 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
120 list_add_tail_rcu(&n_ptr->list, &temp_node->list); 140 list_add_tail_rcu(&n_ptr->list, &temp_node->list);
121 n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN; 141 n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
122 n_ptr->signature = INVALID_NODE_SIG; 142 n_ptr->signature = INVALID_NODE_SIG;
143 tipc_node_get(n_ptr);
123exit: 144exit:
124 spin_unlock_bh(&tn->node_list_lock); 145 spin_unlock_bh(&tn->node_list_lock);
125 return n_ptr; 146 return n_ptr;
126} 147}
127 148
128static void tipc_node_delete(struct tipc_net *tn, struct tipc_node *n_ptr) 149static void tipc_node_delete(struct tipc_node *node)
129{ 150{
130 list_del_rcu(&n_ptr->list); 151 list_del_rcu(&node->list);
131 hlist_del_rcu(&n_ptr->hash); 152 hlist_del_rcu(&node->hash);
132 kfree_rcu(n_ptr, rcu); 153 kfree_rcu(node, rcu);
133} 154}
134 155
135void tipc_node_stop(struct net *net) 156void tipc_node_stop(struct net *net)
@@ -139,7 +160,7 @@ void tipc_node_stop(struct net *net)
139 160
140 spin_lock_bh(&tn->node_list_lock); 161 spin_lock_bh(&tn->node_list_lock);
141 list_for_each_entry_safe(node, t_node, &tn->node_list, list) 162 list_for_each_entry_safe(node, t_node, &tn->node_list, list)
142 tipc_node_delete(tn, node); 163 tipc_node_put(node);
143 spin_unlock_bh(&tn->node_list_lock); 164 spin_unlock_bh(&tn->node_list_lock);
144} 165}
145 166
@@ -147,6 +168,7 @@ int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port)
147{ 168{
148 struct tipc_node *node; 169 struct tipc_node *node;
149 struct tipc_sock_conn *conn; 170 struct tipc_sock_conn *conn;
171 int err = 0;
150 172
151 if (in_own_node(net, dnode)) 173 if (in_own_node(net, dnode))
152 return 0; 174 return 0;
@@ -157,8 +179,10 @@ int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port)
157 return -EHOSTUNREACH; 179 return -EHOSTUNREACH;
158 } 180 }
159 conn = kmalloc(sizeof(*conn), GFP_ATOMIC); 181 conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
160 if (!conn) 182 if (!conn) {
161 return -EHOSTUNREACH; 183 err = -EHOSTUNREACH;
184 goto exit;
185 }
162 conn->peer_node = dnode; 186 conn->peer_node = dnode;
163 conn->port = port; 187 conn->port = port;
164 conn->peer_port = peer_port; 188 conn->peer_port = peer_port;
@@ -166,7 +190,9 @@ int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port)
166 tipc_node_lock(node); 190 tipc_node_lock(node);
167 list_add_tail(&conn->list, &node->conn_sks); 191 list_add_tail(&conn->list, &node->conn_sks);
168 tipc_node_unlock(node); 192 tipc_node_unlock(node);
169 return 0; 193exit:
194 tipc_node_put(node);
195 return err;
170} 196}
171 197
172void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) 198void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
@@ -189,6 +215,7 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
189 kfree(conn); 215 kfree(conn);
190 } 216 }
191 tipc_node_unlock(node); 217 tipc_node_unlock(node);
218 tipc_node_put(node);
192} 219}
193 220
194/** 221/**
@@ -417,19 +444,25 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
417 char *linkname, size_t len) 444 char *linkname, size_t len)
418{ 445{
419 struct tipc_link *link; 446 struct tipc_link *link;
447 int err = -EINVAL;
420 struct tipc_node *node = tipc_node_find(net, addr); 448 struct tipc_node *node = tipc_node_find(net, addr);
421 449
422 if ((bearer_id >= MAX_BEARERS) || !node) 450 if (!node)
423 return -EINVAL; 451 return err;
452
453 if (bearer_id >= MAX_BEARERS)
454 goto exit;
455
424 tipc_node_lock(node); 456 tipc_node_lock(node);
425 link = node->links[bearer_id]; 457 link = node->links[bearer_id];
426 if (link) { 458 if (link) {
427 strncpy(linkname, link->name, len); 459 strncpy(linkname, link->name, len);
428 tipc_node_unlock(node); 460 err = 0;
429 return 0;
430 } 461 }
462exit:
431 tipc_node_unlock(node); 463 tipc_node_unlock(node);
432 return -EINVAL; 464 tipc_node_put(node);
465 return err;
433} 466}
434 467
435void tipc_node_unlock(struct tipc_node *node) 468void tipc_node_unlock(struct tipc_node *node)
@@ -545,17 +578,21 @@ int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
545 msg.seq = cb->nlh->nlmsg_seq; 578 msg.seq = cb->nlh->nlmsg_seq;
546 579
547 rcu_read_lock(); 580 rcu_read_lock();
548 581 if (last_addr) {
549 if (last_addr && !tipc_node_find(net, last_addr)) { 582 node = tipc_node_find(net, last_addr);
550 rcu_read_unlock(); 583 if (!node) {
551 /* We never set seq or call nl_dump_check_consistent() this 584 rcu_read_unlock();
552 * means that setting prev_seq here will cause the consistence 585 /* We never set seq or call nl_dump_check_consistent()
553 * check to fail in the netlink callback handler. Resulting in 586 * this means that setting prev_seq here will cause the
554 * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if 587 * consistence check to fail in the netlink callback
555 * the node state changed while we released the lock. 588 * handler. Resulting in the NLMSG_DONE message having
556 */ 589 * the NLM_F_DUMP_INTR flag set if the node state
557 cb->prev_seq = 1; 590 * changed while we released the lock.
558 return -EPIPE; 591 */
592 cb->prev_seq = 1;
593 return -EPIPE;
594 }
595 tipc_node_put(node);
559 } 596 }
560 597
561 list_for_each_entry_rcu(node, &tn->node_list, list) { 598 list_for_each_entry_rcu(node, &tn->node_list, list) {
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 9629ecd2bdd8..02d5c20dc551 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -94,6 +94,7 @@ struct tipc_node_bclink {
94/** 94/**
95 * struct tipc_node - TIPC node structure 95 * struct tipc_node - TIPC node structure
96 * @addr: network address of node 96 * @addr: network address of node
97 * @ref: reference counter to node object
97 * @lock: spinlock governing access to structure 98 * @lock: spinlock governing access to structure
98 * @net: the applicable net namespace 99 * @net: the applicable net namespace
99 * @hash: links to adjacent nodes in unsorted hash chain 100 * @hash: links to adjacent nodes in unsorted hash chain
@@ -115,6 +116,7 @@ struct tipc_node_bclink {
115 */ 116 */
116struct tipc_node { 117struct tipc_node {
117 u32 addr; 118 u32 addr;
119 struct kref kref;
118 spinlock_t lock; 120 spinlock_t lock;
119 struct net *net; 121 struct net *net;
120 struct hlist_node hash; 122 struct hlist_node hash;
@@ -137,6 +139,7 @@ struct tipc_node {
137}; 139};
138 140
139struct tipc_node *tipc_node_find(struct net *net, u32 addr); 141struct tipc_node *tipc_node_find(struct net *net, u32 addr);
142void tipc_node_put(struct tipc_node *node);
140struct tipc_node *tipc_node_create(struct net *net, u32 addr); 143struct tipc_node *tipc_node_create(struct net *net, u32 addr);
141void tipc_node_stop(struct net *net); 144void tipc_node_stop(struct net *net);
142void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); 145void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
@@ -171,10 +174,12 @@ static inline uint tipc_node_get_mtu(struct net *net, u32 addr, u32 selector)
171 174
172 node = tipc_node_find(net, addr); 175 node = tipc_node_find(net, addr);
173 176
174 if (likely(node)) 177 if (likely(node)) {
175 mtu = node->act_mtus[selector & 1]; 178 mtu = node->act_mtus[selector & 1];
176 else 179 tipc_node_put(node);
180 } else {
177 mtu = MAX_MSG_SIZE; 181 mtu = MAX_MSG_SIZE;
182 }
178 183
179 return mtu; 184 return mtu;
180} 185}