diff options
author | Ying Xue <ying.xue@windriver.com> | 2015-03-26 06:10:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-29 15:40:28 -0400 |
commit | 8a0f6ebe8494c5c6ccfe12264385b64c280e3241 (patch) | |
tree | 2f106a95ffda73b8e8f1596cc95152398cd5379b /net/tipc/link.c | |
parent | b952b2befb6f6b009e91f087285b9a0a6beb1cc8 (diff) |
tipc: involve reference counter for node structure
TIPC node hash node table is protected with rcu lock on read side.
tipc_node_find() is used to look for a node object with node address
through iterating the hash node table. As the entire process of what
tipc_node_find() traverses the table is guarded with rcu read lock,
it's safe for us. However, when callers use the node object returned
by tipc_node_find(), there is no rcu read lock applied. Therefore,
this is absolutely unsafe for callers of tipc_node_find().
Now we introduce a reference counter for node structure. Before
tipc_node_find() returns node object to its caller, it first increases
the reference counter. Accordingly, after its caller used it up,
it decreases the counter again. This can prevent a node being used by
one thread from being freed by another thread.
Reviewed-by: Erik Hugne <erik.hugne@ericsson.com>
Reviewed-by: Jon Maloy <jon.maloy@ericson.com>
Signed-off-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 7 |
1 files changed, 5 insertions, 2 deletions
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 | ||