diff options
-rw-r--r-- | net/tipc/bcast.c | 5 | ||||
-rw-r--r-- | net/tipc/discover.c | 1 | ||||
-rw-r--r-- | net/tipc/link.c | 7 | ||||
-rw-r--r-- | net/tipc/name_distr.c | 2 | ||||
-rw-r--r-- | net/tipc/node.c | 85 | ||||
-rw-r--r-- | net/tipc/node.h | 9 |
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 | ||
571 | unlock: | 571 | unlock: |
572 | tipc_node_unlock(node); | 572 | tipc_node_unlock(node); |
573 | tipc_node_put(node); | ||
573 | exit: | 574 | exit: |
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; |
1206 | unlock: | 1207 | unlock: |
1207 | tipc_node_unlock(n_ptr); | 1208 | tipc_node_unlock(n_ptr); |
1209 | tipc_node_put(n_ptr); | ||
1208 | discard: | 1210 | discard: |
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 | ||
249 | static void tipc_publ_unsubscribe(struct net *net, struct publication *publ, | 250 | static 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 | ||
43 | static void node_lost_contact(struct tipc_node *n_ptr); | 43 | static void node_lost_contact(struct tipc_node *n_ptr); |
44 | static void node_established_contact(struct tipc_node *n_ptr); | 44 | static void node_established_contact(struct tipc_node *n_ptr); |
45 | static void tipc_node_delete(struct tipc_node *node); | ||
45 | 46 | ||
46 | struct tipc_sock_conn { | 47 | struct 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 | ||
71 | static 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 | |||
78 | void tipc_node_put(struct tipc_node *node) | ||
79 | { | ||
80 | kref_put(&node->kref, tipc_node_kref_release); | ||
81 | } | ||
82 | |||
83 | static 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); | ||
123 | exit: | 144 | exit: |
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 | ||
128 | static void tipc_node_delete(struct tipc_net *tn, struct tipc_node *n_ptr) | 149 | static 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 | ||
135 | void tipc_node_stop(struct net *net) | 156 | void 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; | 193 | exit: |
194 | tipc_node_put(node); | ||
195 | return err; | ||
170 | } | 196 | } |
171 | 197 | ||
172 | void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) | 198 | void 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 | } |
462 | exit: | ||
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 | ||
435 | void tipc_node_unlock(struct tipc_node *node) | 468 | void 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 | */ |
116 | struct tipc_node { | 117 | struct 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 | ||
139 | struct tipc_node *tipc_node_find(struct net *net, u32 addr); | 141 | struct tipc_node *tipc_node_find(struct net *net, u32 addr); |
142 | void tipc_node_put(struct tipc_node *node); | ||
140 | struct tipc_node *tipc_node_create(struct net *net, u32 addr); | 143 | struct tipc_node *tipc_node_create(struct net *net, u32 addr); |
141 | void tipc_node_stop(struct net *net); | 144 | void tipc_node_stop(struct net *net); |
142 | void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | 145 | void 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 | } |