aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-03-29 15:40:37 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-29 15:40:37 -0400
commitae7633c841b3d17ab54e372ad9cc0f37a9a7c72d (patch)
tree2f106a95ffda73b8e8f1596cc95152398cd5379b /net
parentfaadb05f4b7f11b3063a20d7fc5afcbf1124dbeb (diff)
parent8a0f6ebe8494c5c6ccfe12264385b64c280e3241 (diff)
Merge branch 'tipc-next'
Ying Xue says: ==================== tipc: fix two corner issues The patch set aims at resolving the following two critical issues: Patch #1: Resolve a deadlock which happens while all links are reset Patch #2: Correct a mistake usage of RCU lock which is used to protect node list ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/tipc/bcast.c28
-rw-r--r--net/tipc/bcast.h4
-rw-r--r--net/tipc/discover.c1
-rw-r--r--net/tipc/link.c12
-rw-r--r--net/tipc/name_distr.c2
-rw-r--r--net/tipc/node.c90
-rw-r--r--net/tipc/node.h12
7 files changed, 87 insertions, 62 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 79355531c3e2..ae558dd7f8ee 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -62,21 +62,8 @@ static void tipc_bclink_lock(struct net *net)
62static void tipc_bclink_unlock(struct net *net) 62static void tipc_bclink_unlock(struct net *net)
63{ 63{
64 struct tipc_net *tn = net_generic(net, tipc_net_id); 64 struct tipc_net *tn = net_generic(net, tipc_net_id);
65 struct tipc_node *node = NULL;
66 65
67 if (likely(!tn->bclink->flags)) {
68 spin_unlock_bh(&tn->bclink->lock);
69 return;
70 }
71
72 if (tn->bclink->flags & TIPC_BCLINK_RESET) {
73 tn->bclink->flags &= ~TIPC_BCLINK_RESET;
74 node = tipc_bclink_retransmit_to(net);
75 }
76 spin_unlock_bh(&tn->bclink->lock); 66 spin_unlock_bh(&tn->bclink->lock);
77
78 if (node)
79 tipc_link_reset_all(node);
80} 67}
81 68
82void tipc_bclink_input(struct net *net) 69void tipc_bclink_input(struct net *net)
@@ -91,13 +78,6 @@ uint tipc_bclink_get_mtu(void)
91 return MAX_PKT_DEFAULT_MCAST; 78 return MAX_PKT_DEFAULT_MCAST;
92} 79}
93 80
94void tipc_bclink_set_flags(struct net *net, unsigned int flags)
95{
96 struct tipc_net *tn = net_generic(net, tipc_net_id);
97
98 tn->bclink->flags |= flags;
99}
100
101static u32 bcbuf_acks(struct sk_buff *buf) 81static u32 bcbuf_acks(struct sk_buff *buf)
102{ 82{
103 return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle; 83 return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle;
@@ -156,7 +136,6 @@ static void bclink_update_last_sent(struct tipc_node *node, u32 seqno)
156 seqno : node->bclink.last_sent; 136 seqno : node->bclink.last_sent;
157} 137}
158 138
159
160/** 139/**
161 * tipc_bclink_retransmit_to - get most recent node to request retransmission 140 * tipc_bclink_retransmit_to - get most recent node to request retransmission
162 * 141 *
@@ -350,13 +329,12 @@ static void bclink_peek_nack(struct net *net, struct tipc_msg *msg)
350 return; 329 return;
351 330
352 tipc_node_lock(n_ptr); 331 tipc_node_lock(n_ptr);
353
354 if (n_ptr->bclink.recv_permitted && 332 if (n_ptr->bclink.recv_permitted &&
355 (n_ptr->bclink.last_in != n_ptr->bclink.last_sent) && 333 (n_ptr->bclink.last_in != n_ptr->bclink.last_sent) &&
356 (n_ptr->bclink.last_in == msg_bcgap_after(msg))) 334 (n_ptr->bclink.last_in == msg_bcgap_after(msg)))
357 n_ptr->bclink.oos_state = 2; 335 n_ptr->bclink.oos_state = 2;
358
359 tipc_node_unlock(n_ptr); 336 tipc_node_unlock(n_ptr);
337 tipc_node_put(n_ptr);
360} 338}
361 339
362/* tipc_bclink_xmit - deliver buffer chain to all nodes in cluster 340/* tipc_bclink_xmit - deliver buffer chain to all nodes in cluster
@@ -476,17 +454,18 @@ void tipc_bclink_rcv(struct net *net, struct sk_buff *buf)
476 goto unlock; 454 goto unlock;
477 if (msg_destnode(msg) == tn->own_addr) { 455 if (msg_destnode(msg) == tn->own_addr) {
478 tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); 456 tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
479 tipc_node_unlock(node);
480 tipc_bclink_lock(net); 457 tipc_bclink_lock(net);
481 bcl->stats.recv_nacks++; 458 bcl->stats.recv_nacks++;
482 tn->bclink->retransmit_to = node; 459 tn->bclink->retransmit_to = node;
483 bclink_retransmit_pkt(tn, msg_bcgap_after(msg), 460 bclink_retransmit_pkt(tn, msg_bcgap_after(msg),
484 msg_bcgap_to(msg)); 461 msg_bcgap_to(msg));
485 tipc_bclink_unlock(net); 462 tipc_bclink_unlock(net);
463 tipc_node_unlock(node);
486 } else { 464 } else {
487 tipc_node_unlock(node); 465 tipc_node_unlock(node);
488 bclink_peek_nack(net, msg); 466 bclink_peek_nack(net, msg);
489 } 467 }
468 tipc_node_put(node);
490 goto exit; 469 goto exit;
491 } 470 }
492 471
@@ -591,6 +570,7 @@ receive:
591 570
592unlock: 571unlock:
593 tipc_node_unlock(node); 572 tipc_node_unlock(node);
573 tipc_node_put(node);
594exit: 574exit:
595 kfree_skb(buf); 575 kfree_skb(buf);
596} 576}
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index 43f397fbac55..4bdc12277d33 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -55,7 +55,6 @@ struct tipc_bcbearer_pair {
55 struct tipc_bearer *secondary; 55 struct tipc_bearer *secondary;
56}; 56};
57 57
58#define TIPC_BCLINK_RESET 1
59#define BCBEARER MAX_BEARERS 58#define BCBEARER MAX_BEARERS
60 59
61/** 60/**
@@ -86,7 +85,6 @@ struct tipc_bcbearer {
86 * @lock: spinlock governing access to structure 85 * @lock: spinlock governing access to structure
87 * @link: (non-standard) broadcast link structure 86 * @link: (non-standard) broadcast link structure
88 * @node: (non-standard) node structure representing b'cast link's peer node 87 * @node: (non-standard) node structure representing b'cast link's peer node
89 * @flags: represent bclink states
90 * @bcast_nodes: map of broadcast-capable nodes 88 * @bcast_nodes: map of broadcast-capable nodes
91 * @retransmit_to: node that most recently requested a retransmit 89 * @retransmit_to: node that most recently requested a retransmit
92 * 90 *
@@ -96,7 +94,6 @@ struct tipc_bclink {
96 spinlock_t lock; 94 spinlock_t lock;
97 struct tipc_link link; 95 struct tipc_link link;
98 struct tipc_node node; 96 struct tipc_node node;
99 unsigned int flags;
100 struct sk_buff_head arrvq; 97 struct sk_buff_head arrvq;
101 struct sk_buff_head inputq; 98 struct sk_buff_head inputq;
102 struct tipc_node_map bcast_nodes; 99 struct tipc_node_map bcast_nodes;
@@ -117,7 +114,6 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a,
117 114
118int tipc_bclink_init(struct net *net); 115int tipc_bclink_init(struct net *net);
119void tipc_bclink_stop(struct net *net); 116void tipc_bclink_stop(struct net *net);
120void tipc_bclink_set_flags(struct net *tn, unsigned int flags);
121void tipc_bclink_add_node(struct net *net, u32 addr); 117void tipc_bclink_add_node(struct net *net, u32 addr);
122void tipc_bclink_remove_node(struct net *net, u32 addr); 118void tipc_bclink_remove_node(struct net *net, u32 addr);
123struct tipc_node *tipc_bclink_retransmit_to(struct net *tn); 119struct tipc_node *tipc_bclink_retransmit_to(struct net *tn);
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 1287161e9424..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;
@@ -980,7 +981,6 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,
980 (unsigned long) TIPC_SKB_CB(buf)->handle); 981 (unsigned long) TIPC_SKB_CB(buf)->handle);
981 982
982 n_ptr = tipc_bclink_retransmit_to(net); 983 n_ptr = tipc_bclink_retransmit_to(net);
983 tipc_node_lock(n_ptr);
984 984
985 tipc_addr_string_fill(addr_string, n_ptr->addr); 985 tipc_addr_string_fill(addr_string, n_ptr->addr);
986 pr_info("Broadcast link info for %s\n", addr_string); 986 pr_info("Broadcast link info for %s\n", addr_string);
@@ -992,9 +992,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,
992 n_ptr->bclink.oos_state, 992 n_ptr->bclink.oos_state,
993 n_ptr->bclink.last_sent); 993 n_ptr->bclink.last_sent);
994 994
995 tipc_node_unlock(n_ptr); 995 n_ptr->action_flags |= TIPC_BCAST_RESET;
996
997 tipc_bclink_set_flags(net, TIPC_BCLINK_RESET);
998 l_ptr->stale_count = 0; 996 l_ptr->stale_count = 0;
999 } 997 }
1000} 998}
@@ -1119,8 +1117,8 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)
1119 n_ptr = tipc_node_find(net, msg_prevnode(msg)); 1117 n_ptr = tipc_node_find(net, msg_prevnode(msg));
1120 if (unlikely(!n_ptr)) 1118 if (unlikely(!n_ptr))
1121 goto discard; 1119 goto discard;
1122 tipc_node_lock(n_ptr);
1123 1120
1121 tipc_node_lock(n_ptr);
1124 /* Locate unicast link endpoint that should handle message */ 1122 /* Locate unicast link endpoint that should handle message */
1125 l_ptr = n_ptr->links[b_ptr->identity]; 1123 l_ptr = n_ptr->links[b_ptr->identity];
1126 if (unlikely(!l_ptr)) 1124 if (unlikely(!l_ptr))
@@ -1208,6 +1206,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)
1208 skb = NULL; 1206 skb = NULL;
1209unlock: 1207unlock:
1210 tipc_node_unlock(n_ptr); 1208 tipc_node_unlock(n_ptr);
1209 tipc_node_put(n_ptr);
1211discard: 1210discard:
1212 if (unlikely(skb)) 1211 if (unlikely(skb))
1213 kfree_skb(skb); 1212 kfree_skb(skb);
@@ -2239,7 +2238,6 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
2239 msg.seq = cb->nlh->nlmsg_seq; 2238 msg.seq = cb->nlh->nlmsg_seq;
2240 2239
2241 rcu_read_lock(); 2240 rcu_read_lock();
2242
2243 if (prev_node) { 2241 if (prev_node) {
2244 node = tipc_node_find(net, prev_node); 2242 node = tipc_node_find(net, prev_node);
2245 if (!node) { 2243 if (!node) {
@@ -2252,6 +2250,7 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
2252 cb->prev_seq = 1; 2250 cb->prev_seq = 1;
2253 goto out; 2251 goto out;
2254 } 2252 }
2253 tipc_node_put(node);
2255 2254
2256 list_for_each_entry_continue_rcu(node, &tn->node_list, 2255 list_for_each_entry_continue_rcu(node, &tn->node_list,
2257 list) { 2256 list) {
@@ -2259,6 +2258,7 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
2259 err = __tipc_nl_add_node_links(net, &msg, node, 2258 err = __tipc_nl_add_node_links(net, &msg, node,
2260 &prev_link); 2259 &prev_link);
2261 tipc_node_unlock(node); 2260 tipc_node_unlock(node);
2261 tipc_node_put(node);
2262 if (err) 2262 if (err)
2263 goto out; 2263 goto out;
2264 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 26d1de1bf34d..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)
@@ -459,7 +492,7 @@ void tipc_node_unlock(struct tipc_node *node)
459 TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP | 492 TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP |
460 TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP | 493 TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP |
461 TIPC_WAKEUP_BCAST_USERS | TIPC_BCAST_MSG_EVT | 494 TIPC_WAKEUP_BCAST_USERS | TIPC_BCAST_MSG_EVT |
462 TIPC_NAMED_MSG_EVT); 495 TIPC_NAMED_MSG_EVT | TIPC_BCAST_RESET);
463 496
464 spin_unlock_bh(&node->lock); 497 spin_unlock_bh(&node->lock);
465 498
@@ -488,6 +521,9 @@ void tipc_node_unlock(struct tipc_node *node)
488 521
489 if (flags & TIPC_BCAST_MSG_EVT) 522 if (flags & TIPC_BCAST_MSG_EVT)
490 tipc_bclink_input(net); 523 tipc_bclink_input(net);
524
525 if (flags & TIPC_BCAST_RESET)
526 tipc_link_reset_all(node);
491} 527}
492 528
493/* Caller should hold node lock for the passed node */ 529/* Caller should hold node lock for the passed node */
@@ -542,17 +578,21 @@ int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
542 msg.seq = cb->nlh->nlmsg_seq; 578 msg.seq = cb->nlh->nlmsg_seq;
543 579
544 rcu_read_lock(); 580 rcu_read_lock();
545 581 if (last_addr) {
546 if (last_addr && !tipc_node_find(net, last_addr)) { 582 node = tipc_node_find(net, last_addr);
547 rcu_read_unlock(); 583 if (!node) {
548 /* We never set seq or call nl_dump_check_consistent() this 584 rcu_read_unlock();
549 * means that setting prev_seq here will cause the consistence 585 /* We never set seq or call nl_dump_check_consistent()
550 * check to fail in the netlink callback handler. Resulting in 586 * this means that setting prev_seq here will cause the
551 * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if 587 * consistence check to fail in the netlink callback
552 * the node state changed while we released the lock. 588 * handler. Resulting in the NLMSG_DONE message having
553 */ 589 * the NLM_F_DUMP_INTR flag set if the node state
554 cb->prev_seq = 1; 590 * changed while we released the lock.
555 return -EPIPE; 591 */
592 cb->prev_seq = 1;
593 return -EPIPE;
594 }
595 tipc_node_put(node);
556 } 596 }
557 597
558 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 e89ac04ec2c3..02d5c20dc551 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -64,7 +64,8 @@ enum {
64 TIPC_NOTIFY_LINK_UP = (1 << 6), 64 TIPC_NOTIFY_LINK_UP = (1 << 6),
65 TIPC_NOTIFY_LINK_DOWN = (1 << 7), 65 TIPC_NOTIFY_LINK_DOWN = (1 << 7),
66 TIPC_NAMED_MSG_EVT = (1 << 8), 66 TIPC_NAMED_MSG_EVT = (1 << 8),
67 TIPC_BCAST_MSG_EVT = (1 << 9) 67 TIPC_BCAST_MSG_EVT = (1 << 9),
68 TIPC_BCAST_RESET = (1 << 10)
68}; 69};
69 70
70/** 71/**
@@ -93,6 +94,7 @@ struct tipc_node_bclink {
93/** 94/**
94 * struct tipc_node - TIPC node structure 95 * struct tipc_node - TIPC node structure
95 * @addr: network address of node 96 * @addr: network address of node
97 * @ref: reference counter to node object
96 * @lock: spinlock governing access to structure 98 * @lock: spinlock governing access to structure
97 * @net: the applicable net namespace 99 * @net: the applicable net namespace
98 * @hash: links to adjacent nodes in unsorted hash chain 100 * @hash: links to adjacent nodes in unsorted hash chain
@@ -114,6 +116,7 @@ struct tipc_node_bclink {
114 */ 116 */
115struct tipc_node { 117struct tipc_node {
116 u32 addr; 118 u32 addr;
119 struct kref kref;
117 spinlock_t lock; 120 spinlock_t lock;
118 struct net *net; 121 struct net *net;
119 struct hlist_node hash; 122 struct hlist_node hash;
@@ -136,6 +139,7 @@ struct tipc_node {
136}; 139};
137 140
138struct 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);
139struct tipc_node *tipc_node_create(struct net *net, u32 addr); 143struct tipc_node *tipc_node_create(struct net *net, u32 addr);
140void tipc_node_stop(struct net *net); 144void tipc_node_stop(struct net *net);
141void 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);
@@ -170,10 +174,12 @@ static inline uint tipc_node_get_mtu(struct net *net, u32 addr, u32 selector)
170 174
171 node = tipc_node_find(net, addr); 175 node = tipc_node_find(net, addr);
172 176
173 if (likely(node)) 177 if (likely(node)) {
174 mtu = node->act_mtus[selector & 1]; 178 mtu = node->act_mtus[selector & 1];
175 else 179 tipc_node_put(node);
180 } else {
176 mtu = MAX_MSG_SIZE; 181 mtu = MAX_MSG_SIZE;
182 }
177 183
178 return mtu; 184 return mtu;
179} 185}