[tipc-discussion] [PATCH 0/2] New node removal netlink command
Add a new netlink command that can remove a dead node from the internal data structures. There is still an impediment here: When I wrote this a node was removed properly on the first call. After rebase it now requires the netlink command and the subsequent tipc_node_stop() function to be executed twice before the node is actually removed. To me this suggests that something is wrong with the node ref-count. I bisected and found the change in behaviour to be introduced in 5405ff6e15f4 tipc: convert node lock to rwlock Looking at that commit the only change in ref-counting that I can spot is new return at line 463 of the patch: if (likely(!skb_queue_empty(&xmitq))) ... return ... Taking this return would result in one less tipc_node_put(). I'm not familiar with how the node ref counting is suppose to work. Can someone help me here? Why are we changing the ref count of a node in the transmit function? Richard Alpe (2): tipc: move netlink policies to netlink.h tipc: add node removal functionality include/uapi/linux/tipc_netlink.h | 1 + net/tipc/bearer.c | 19 + net/tipc/link.c | 8 net/tipc/name_table.c | 7 +--- net/tipc/net.c| 8 +--- net/tipc/netlink.c| 18 +++-- net/tipc/netlink.h| 85 +++ net/tipc/node.c | 83 +- net/tipc/node.h | 3 +- net/tipc/socket.c | 9 + net/tipc/udp_media.c | 9 + 11 files changed, 155 insertions(+), 95 deletions(-) -- 2.1.4 -- Go from Idea to Many App Stores Faster with Intel(R) XDK Give your users amazing mobile app experiences with Intel(R) XDK. Use one codebase in this all-in-one HTML5 development environment. Design, debug & build mobile apps & 2D/3D high-impact games for multiple OSs. http://pubads.g.doubleclick.net/gampad/clk?id=254741911&iu=/4140 ___ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion
[tipc-discussion] [PATCH 1/2] tipc: move netlink policies to netlink.h
Make the c files less cluttered and enable netlink attributes to be shared between files. This will prove useful in future patches where a node message contains a nested network. Signed-off-by: Richard Alpe --- net/tipc/bearer.c | 19 +--- net/tipc/link.c | 8 - net/tipc/name_table.c | 7 + net/tipc/net.c| 6 +--- net/tipc/netlink.c| 13 +--- net/tipc/netlink.h| 85 +++ net/tipc/node.c | 23 +- net/tipc/socket.c | 9 +- net/tipc/udp_media.c | 9 +- 9 files changed, 92 insertions(+), 87 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 802ffad..d654cfe 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -40,6 +40,7 @@ #include "link.h" #include "discover.h" #include "bcast.h" +#include "netlink.h" #define MAX_ADDR_STR 60 @@ -53,24 +54,6 @@ static struct tipc_media * const media_info_array[] = { #endif NULL }; - -static const struct nla_policy -tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = { - [TIPC_NLA_BEARER_UNSPEC]= { .type = NLA_UNSPEC }, - [TIPC_NLA_BEARER_NAME] = { - .type = NLA_STRING, - .len = TIPC_MAX_BEARER_NAME - }, - [TIPC_NLA_BEARER_PROP] = { .type = NLA_NESTED }, - [TIPC_NLA_BEARER_DOMAIN]= { .type = NLA_U32 } -}; - -static const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX + 1] = { - [TIPC_NLA_MEDIA_UNSPEC] = { .type = NLA_UNSPEC }, - [TIPC_NLA_MEDIA_NAME] = { .type = NLA_STRING }, - [TIPC_NLA_MEDIA_PROP] = { .type = NLA_NESTED } -}; - static void bearer_disable(struct net *net, struct tipc_bearer *b); /** diff --git a/net/tipc/link.c b/net/tipc/link.c index b11afe7..5f7fa42 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -196,14 +196,6 @@ struct tipc_link { static const char *link_co_err = "Link tunneling error, "; static const char *link_rst_msg = "Resetting link "; -/* Properties valid for media, bearar and link */ -static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { - [TIPC_NLA_PROP_UNSPEC] = { .type = NLA_UNSPEC }, - [TIPC_NLA_PROP_PRIO]= { .type = NLA_U32 }, - [TIPC_NLA_PROP_TOL] = { .type = NLA_U32 }, - [TIPC_NLA_PROP_WIN] = { .type = NLA_U32 } -}; - /* Send states for broadcast NACKs */ enum { diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 91fce70..75992b5 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -44,15 +44,10 @@ #include "addr.h" #include "node.h" #include +#include "netlink.h" #define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */ -static const struct nla_policy -tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = { - [TIPC_NLA_NAME_TABLE_UNSPEC]= { .type = NLA_UNSPEC }, - [TIPC_NLA_NAME_TABLE_PUBL] = { .type = NLA_NESTED } -}; - /** * struct name_info - name sequence publication info * @node_list: circular list of publications made by own node diff --git a/net/tipc/net.c b/net/tipc/net.c index 77bf911..d7a5c11 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -41,11 +41,7 @@ #include "socket.h" #include "node.h" #include "bcast.h" - -static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = { - [TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC }, - [TIPC_NLA_NET_ID] = { .type = NLA_U32 } -}; +#include "netlink.h" /* * The TIPC locking policy is designed to ensure a very fine locking diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 8975b01..234cb93 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -42,18 +42,7 @@ #include "node.h" #include "net.h" #include - -static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = { - [TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, }, - [TIPC_NLA_BEARER] = { .type = NLA_NESTED, }, - [TIPC_NLA_SOCK] = { .type = NLA_NESTED, }, - [TIPC_NLA_PUBL] = { .type = NLA_NESTED, }, - [TIPC_NLA_LINK] = { .type = NLA_NESTED, }, - [TIPC_NLA_MEDIA]= { .type = NLA_NESTED, }, - [TIPC_NLA_NODE] = { .type = NLA_NESTED, }, - [TIPC_NLA_NET] = { .type = NLA_NESTED, }, - [TIPC_NLA_NAME_TABLE] = { .type = NLA_NESTED, } -}; +#include "netlink.h" /* Users of the legacy API (tipc-config) can't handle that we add operations, * so we have a separate genl handling for the new API. diff --git a/net/tipc/netlink.h b/net/tipc/netlink.h index 08a1db6..ff7a39da 100644 --- a/net/tipc/netlink.h +++ b/net/tipc/netlink.h @@ -36,7 +36,92 @@ #ifndef _TIPC_NETLINK_H #define _TIPC_NETLINK_H +#include + extern struct genl_family tipc_genl_family; + +static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = { + [TIPC_NLA_UNSPEC] = {
[tipc-discussion] [PATCH 2/2] tipc: add node removal functionality
Add a new netlink command, TIPC_NL_NODE_REMOVE. This command can remove an offline peer node from the internal data structures. This will be supported by the tipc user space tool in iproute2. Signed-off-by: Richard Alpe --- include/uapi/linux/tipc_netlink.h | 1 + net/tipc/net.c| 2 +- net/tipc/netlink.c| 5 net/tipc/node.c | 60 +++ net/tipc/node.h | 3 +- 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h index d4c8f14..3f8a2b8 100644 --- a/include/uapi/linux/tipc_netlink.h +++ b/include/uapi/linux/tipc_netlink.h @@ -56,6 +56,7 @@ enum { TIPC_NL_NET_GET, TIPC_NL_NET_SET, TIPC_NL_NAME_TABLE_GET, + TIPC_NL_NODE_REMOVE, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 diff --git a/net/tipc/net.c b/net/tipc/net.c index d7a5c11..bc6b4a6 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -135,7 +135,7 @@ void tipc_net_stop(struct net *net) tn->own_addr); rtnl_lock(); tipc_bearer_stop(net); - tipc_node_stop(net); + tipc_node_stop_net(net); rtnl_unlock(); pr_info("Left network mode\n"); diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 234cb93..3566832 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -134,6 +134,11 @@ static const struct genl_ops tipc_genl_v2_ops[] = { .cmd= TIPC_NL_NAME_TABLE_GET, .dumpit = tipc_nl_name_table_dump, .policy = tipc_nl_policy, + }, + { + .cmd= TIPC_NL_NODE_REMOVE, + .doit = tipc_nl_node_rm, + .policy = tipc_nl_policy, } }; diff --git a/net/tipc/node.c b/net/tipc/node.c index 6182d9d..31f40cc 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -378,17 +378,21 @@ static void tipc_node_delete(struct tipc_node *node) kfree_rcu(node, rcu); } -void tipc_node_stop(struct net *net) +static void tipc_node_stop(struct tipc_node *node) +{ + if (del_timer(&node->timer)) + tipc_node_put(node); + tipc_node_put(node); +} + +void tipc_node_stop_net(struct net *net) { struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_node *node, *t_node; spin_lock_bh(&tn->node_list_lock); - list_for_each_entry_safe(node, t_node, &tn->node_list, list) { - if (del_timer(&node->timer)) - tipc_node_put(node); - tipc_node_put(node); - } + list_for_each_entry_safe(node, t_node, &tn->node_list, list) + tipc_node_stop(node); spin_unlock_bh(&tn->node_list_lock); } @@ -1509,6 +1513,50 @@ discard: kfree_skb(skb); } +int tipc_nl_node_rm(struct sk_buff *skb, struct genl_info *info) +{ + u32 addr; + struct net *net = sock_net(skb->sk); + struct nlattr *attrs[TIPC_NLA_NET_MAX + 1]; + struct tipc_net *tn = net_generic(net, tipc_net_id); + struct tipc_node *node; + int err; + + /* We identify the node by its net */ + if (!info->attrs[TIPC_NLA_NET]) + return -EINVAL; + + err = nla_parse_nested(attrs, TIPC_NLA_NET_MAX, + info->attrs[TIPC_NLA_NET], + tipc_nl_net_policy); + if (err) + return err; + + if (!attrs[TIPC_NLA_NET_ADDR]) + return -EINVAL; + + addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]); + + spin_lock_bh(&tn->node_list_lock); + list_for_each_entry_rcu(node, &tn->node_list, list) { + if (node->addr != addr) + continue; + + if (node->state == SELF_DOWN_PEER_DOWN || + node->state == SELF_DOWN_PEER_LEAVING) { + tipc_node_stop(node); + + spin_unlock_bh(&tn->node_list_lock); + return 0; + } + spin_unlock_bh(&tn->node_list_lock); + return -EBUSY; + } + spin_unlock_bh(&tn->node_list_lock); + + return -ENXIO; +} + int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) { int err; diff --git a/net/tipc/node.h b/net/tipc/node.h index f39d9d0..d6250ec 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -51,7 +51,7 @@ enum { #define TIPC_NODE_CAPABILITIES TIPC_BCAST_SYNCH #define INVALID_BEARER_ID -1 -void tipc_node_stop(struct net *net); +void tipc_node_stop_net(struct net *net); void tipc_node_check_dest(struct net *net, u32 onode, struct tipc_bearer *bearer, u16 capabilities, u32 signature, @@ -75,5 +75,6 @@ int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb); int tipc_nl_node_reset_link_stats(struc
Re: [tipc-discussion] [PATCH 0/2] New node removal netlink command
> -Original Message- > From: Richard Alpe > Sent: Wednesday, 02 December, 2015 07:52 > To: tipc-discussion@lists.sourceforge.net > Cc: Jon Maloy; Ying Xue; Richard Alpe > Subject: [PATCH 0/2] New node removal netlink command > > Add a new netlink command that can remove a dead node from the internal > data structures. > > There is still an impediment here: > > When I wrote this a node was removed properly on the first call. After > rebase it now requires the netlink command and the subsequent > tipc_node_stop() function to be executed twice before the node is actually > removed. To me this suggests that something is wrong with the node ref- > count. I bisected and found the change in behaviour to be introduced in > 5405ff6e15f4 tipc: convert node lock to rwlock > > Looking at that commit the only change in ref-counting that I can spot is new > return at line 463 of the patch: > if (likely(!skb_queue_empty(&xmitq))) > ... > return ... > Yes, this is clearly a bug. I will post a patch. Thank you for spotting this. ///jon > Taking this return would result in one less tipc_node_put(). I'm not familiar > with how the node ref counting is suppose to work. Can someone help me > here? > Why are we changing the ref count of a node in the transmit function? > > Richard Alpe (2): > tipc: move netlink policies to netlink.h > tipc: add node removal functionality > > include/uapi/linux/tipc_netlink.h | 1 + > net/tipc/bearer.c | 19 + > net/tipc/link.c | 8 > net/tipc/name_table.c | 7 +--- > net/tipc/net.c| 8 +--- > net/tipc/netlink.c| 18 +++-- > net/tipc/netlink.h| 85 > +++ > net/tipc/node.c | 83 +- > net/tipc/node.h | 3 +- > net/tipc/socket.c | 9 + > net/tipc/udp_media.c | 9 + > 11 files changed, 155 insertions(+), 95 deletions(-) > > -- > 2.1.4 -- Go from Idea to Many App Stores Faster with Intel(R) XDK Give your users amazing mobile app experiences with Intel(R) XDK. Use one codebase in this all-in-one HTML5 development environment. Design, debug & build mobile apps & 2D/3D high-impact games for multiple OSs. http://pubads.g.doubleclick.net/gampad/clk?id=254741911&iu=/4140 ___ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion
Re: [tipc-discussion] [PATCH 1/2] tipc: move netlink policies to netlink.h
Very appreciated change. Maybe you should add the standard phrase "There are no functional changes in this commit" Acked-by: me ///jon > -Original Message- > From: Richard Alpe > Sent: Wednesday, 02 December, 2015 07:52 > To: tipc-discussion@lists.sourceforge.net > Cc: Jon Maloy; Ying Xue; Richard Alpe > Subject: [PATCH 1/2] tipc: move netlink policies to netlink.h > > Make the c files less cluttered and enable netlink attributes to be shared > between files. This will prove useful in future patches where a node message > contains a nested network. > > Signed-off-by: Richard Alpe > --- > net/tipc/bearer.c | 19 +--- > net/tipc/link.c | 8 - > net/tipc/name_table.c | 7 + > net/tipc/net.c| 6 +--- > net/tipc/netlink.c| 13 +--- > net/tipc/netlink.h| 85 > +++ > net/tipc/node.c | 23 +- > net/tipc/socket.c | 9 +- > net/tipc/udp_media.c | 9 +- > 9 files changed, 92 insertions(+), 87 deletions(-) > > diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 802ffad..d654cfe > 100644 > --- a/net/tipc/bearer.c > +++ b/net/tipc/bearer.c > @@ -40,6 +40,7 @@ > #include "link.h" > #include "discover.h" > #include "bcast.h" > +#include "netlink.h" > > #define MAX_ADDR_STR 60 > > @@ -53,24 +54,6 @@ static struct tipc_media * const media_info_array[] = { > #endif > NULL > }; > - > -static const struct nla_policy > -tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = { > - [TIPC_NLA_BEARER_UNSPEC]= { .type = NLA_UNSPEC }, > - [TIPC_NLA_BEARER_NAME] = { > - .type = NLA_STRING, > - .len = TIPC_MAX_BEARER_NAME > - }, > - [TIPC_NLA_BEARER_PROP] = { .type = > NLA_NESTED }, > - [TIPC_NLA_BEARER_DOMAIN]= { .type = NLA_U32 } > -}; > - > -static const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX > + 1] = { > - [TIPC_NLA_MEDIA_UNSPEC] = { .type = NLA_UNSPEC }, > - [TIPC_NLA_MEDIA_NAME] = { .type = NLA_STRING }, > - [TIPC_NLA_MEDIA_PROP] = { .type = NLA_NESTED } > -}; > - > static void bearer_disable(struct net *net, struct tipc_bearer *b); > > /** > diff --git a/net/tipc/link.c b/net/tipc/link.c index b11afe7..5f7fa42 100644 > --- a/net/tipc/link.c > +++ b/net/tipc/link.c > @@ -196,14 +196,6 @@ struct tipc_link { > static const char *link_co_err = "Link tunneling error, "; static const char > *link_rst_msg = "Resetting link "; > > -/* Properties valid for media, bearar and link */ -static const struct > nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { > - [TIPC_NLA_PROP_UNSPEC] = { .type = NLA_UNSPEC }, > - [TIPC_NLA_PROP_PRIO]= { .type = NLA_U32 }, > - [TIPC_NLA_PROP_TOL] = { .type = NLA_U32 }, > - [TIPC_NLA_PROP_WIN] = { .type = NLA_U32 } > -}; > - > /* Send states for broadcast NACKs > */ > enum { > diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index > 91fce70..75992b5 100644 > --- a/net/tipc/name_table.c > +++ b/net/tipc/name_table.c > @@ -44,15 +44,10 @@ > #include "addr.h" > #include "node.h" > #include > +#include "netlink.h" > > #define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */ > > -static const struct nla_policy > -tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = { > - [TIPC_NLA_NAME_TABLE_UNSPEC]= { .type = NLA_UNSPEC }, > - [TIPC_NLA_NAME_TABLE_PUBL] = { .type = NLA_NESTED } > -}; > - > /** > * struct name_info - name sequence publication info > * @node_list: circular list of publications made by own node diff --git > a/net/tipc/net.c b/net/tipc/net.c index 77bf911..d7a5c11 100644 > --- a/net/tipc/net.c > +++ b/net/tipc/net.c > @@ -41,11 +41,7 @@ > #include "socket.h" > #include "node.h" > #include "bcast.h" > - > -static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = > { > - [TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC }, > - [TIPC_NLA_NET_ID] = { .type = NLA_U32 } > -}; > +#include "netlink.h" > > /* > * The TIPC locking policy is designed to ensure a very fine locking diff > --git > a/net/tipc/netlink.c b/net/tipc/netlink.c index 8975b01..234cb93 100644 > --- a/net/tipc/netlink.c > +++ b/net/tipc/netlink.c > @@ -42,18 +42,7 @@ > #include "node.h" > #include "net.h" > #include > - > -static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = { > - [TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, }, > - [TIPC_NLA_BEARER] = { .type = NLA_NESTED, }, > - [TIPC_NLA_SOCK] = { .type = NLA_NESTED, }, > - [TIPC_NLA_PUBL] = { .type = NLA_NESTED, }, > - [TIPC_NLA_LINK] = { .type = NLA_NESTED, }, > - [TIPC_NLA_MEDIA]= { .type = NLA_NESTED, }, > - [TIPC_NLA_NODE] = { .type = NLA_NESTED, }, > - [TIPC_NLA_NET] = { .type = NLA_NESTED, }, >
Re: [tipc-discussion] [PATCH 2/2] tipc: add node removal functionality
Looks good. Reviewed-by: me ///jon > -Original Message- > From: Richard Alpe > Sent: Wednesday, 02 December, 2015 07:52 > To: tipc-discussion@lists.sourceforge.net > Cc: Jon Maloy; Ying Xue; Richard Alpe > Subject: [PATCH 2/2] tipc: add node removal functionality > > Add a new netlink command, TIPC_NL_NODE_REMOVE. This command can > remove an offline peer node from the internal data structures. > > This will be supported by the tipc user space tool in iproute2. > > Signed-off-by: Richard Alpe > --- > include/uapi/linux/tipc_netlink.h | 1 + > net/tipc/net.c| 2 +- > net/tipc/netlink.c| 5 > net/tipc/node.c | 60 +++- > --- > net/tipc/node.h | 3 +- > 5 files changed, 63 insertions(+), 8 deletions(-) > > diff --git a/include/uapi/linux/tipc_netlink.h > b/include/uapi/linux/tipc_netlink.h > index d4c8f14..3f8a2b8 100644 > --- a/include/uapi/linux/tipc_netlink.h > +++ b/include/uapi/linux/tipc_netlink.h > @@ -56,6 +56,7 @@ enum { > TIPC_NL_NET_GET, > TIPC_NL_NET_SET, > TIPC_NL_NAME_TABLE_GET, > + TIPC_NL_NODE_REMOVE, > > __TIPC_NL_CMD_MAX, > TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 diff --git > a/net/tipc/net.c b/net/tipc/net.c index d7a5c11..bc6b4a6 100644 > --- a/net/tipc/net.c > +++ b/net/tipc/net.c > @@ -135,7 +135,7 @@ void tipc_net_stop(struct net *net) > tn->own_addr); > rtnl_lock(); > tipc_bearer_stop(net); > - tipc_node_stop(net); > + tipc_node_stop_net(net); > rtnl_unlock(); > > pr_info("Left network mode\n"); > diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 234cb93..3566832 > 100644 > --- a/net/tipc/netlink.c > +++ b/net/tipc/netlink.c > @@ -134,6 +134,11 @@ static const struct genl_ops tipc_genl_v2_ops[] = { > .cmd= TIPC_NL_NAME_TABLE_GET, > .dumpit = tipc_nl_name_table_dump, > .policy = tipc_nl_policy, > + }, > + { > + .cmd= TIPC_NL_NODE_REMOVE, > + .doit = tipc_nl_node_rm, > + .policy = tipc_nl_policy, > } > }; > > diff --git a/net/tipc/node.c b/net/tipc/node.c index 6182d9d..31f40cc 100644 > --- a/net/tipc/node.c > +++ b/net/tipc/node.c > @@ -378,17 +378,21 @@ static void tipc_node_delete(struct tipc_node > *node) > kfree_rcu(node, rcu); > } > > -void tipc_node_stop(struct net *net) > +static void tipc_node_stop(struct tipc_node *node) { > + if (del_timer(&node->timer)) > + tipc_node_put(node); > + tipc_node_put(node); > +} > + > +void tipc_node_stop_net(struct net *net) > { > struct tipc_net *tn = net_generic(net, tipc_net_id); > struct tipc_node *node, *t_node; > > spin_lock_bh(&tn->node_list_lock); > - list_for_each_entry_safe(node, t_node, &tn->node_list, list) { > - if (del_timer(&node->timer)) > - tipc_node_put(node); > - tipc_node_put(node); > - } > + list_for_each_entry_safe(node, t_node, &tn->node_list, list) > + tipc_node_stop(node); > spin_unlock_bh(&tn->node_list_lock); > } > > @@ -1509,6 +1513,50 @@ discard: > kfree_skb(skb); > } > > +int tipc_nl_node_rm(struct sk_buff *skb, struct genl_info *info) { > + u32 addr; > + struct net *net = sock_net(skb->sk); > + struct nlattr *attrs[TIPC_NLA_NET_MAX + 1]; > + struct tipc_net *tn = net_generic(net, tipc_net_id); > + struct tipc_node *node; > + int err; > + > + /* We identify the node by its net */ > + if (!info->attrs[TIPC_NLA_NET]) > + return -EINVAL; > + > + err = nla_parse_nested(attrs, TIPC_NLA_NET_MAX, > +info->attrs[TIPC_NLA_NET], > +tipc_nl_net_policy); > + if (err) > + return err; > + > + if (!attrs[TIPC_NLA_NET_ADDR]) > + return -EINVAL; > + > + addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]); > + > + spin_lock_bh(&tn->node_list_lock); > + list_for_each_entry_rcu(node, &tn->node_list, list) { > + if (node->addr != addr) > + continue; > + > + if (node->state == SELF_DOWN_PEER_DOWN || > + node->state == SELF_DOWN_PEER_LEAVING) { > + tipc_node_stop(node); > + > + spin_unlock_bh(&tn->node_list_lock); > + return 0; > + } > + spin_unlock_bh(&tn->node_list_lock); > + return -EBUSY; > + } > + spin_unlock_bh(&tn->node_list_lock); > + > + return -ENXIO; > +} > + > int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) { > int err; > diff --git a/net/tipc/node.h b/net/tipc/node.h index f39d9d0..d6250ec > 100644 > --- a/net/tipc/node.h > +++ b/net/tipc/node.h > @@ -51,7 +51,7 @@ enum { > #define TIPC_NODE_CAPABILITIES TIPC_BCAST_SYNCH #define
[tipc-discussion] [PATCH net-next 1/1] tipc: fix node reference count bug
Commit 5405ff6e15f40f2f ("tipc: convert node lock to rwlock") introduced a bug to the node reference counter handling. When a message is successfully sent in the function tipc_node_xmit(), we return directly after releasing the node lock, instead of continuing and decrementing the node reference counter as we should do. This commit fixes this bug. Signed-off-by: Jon Maloy --- net/tipc/node.c | 15 +++ 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 3f7a4ed..fa97d96 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1189,20 +1189,19 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list, spin_unlock_bh(&le->lock); } tipc_node_read_unlock(n); - if (likely(!skb_queue_empty(&xmitq))) { + if (likely(!rc)) tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr); - return 0; - } - if (unlikely(rc == -ENOBUFS)) + else if (rc == -ENOBUFS) tipc_node_link_down(n, bearer_id, false); tipc_node_put(n); return rc; } - if (unlikely(!in_own_node(net, dnode))) - return rc; - tipc_sk_rcv(net, list); - return 0; + if (likely(in_own_node(net, dnode))) { + tipc_sk_rcv(net, list); + return 0; + } + return rc; } /* tipc_node_xmit_skb(): send single buffer to destination -- 1.9.1 -- Go from Idea to Many App Stores Faster with Intel(R) XDK Give your users amazing mobile app experiences with Intel(R) XDK. Use one codebase in this all-in-one HTML5 development environment. Design, debug & build mobile apps & 2D/3D high-impact games for multiple OSs. http://pubads.g.doubleclick.net/gampad/clk?id=254741911&iu=/4140 ___ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion