aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/netlink_compat.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-02-14 14:46:33 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-14 14:46:33 -0500
commit080fe7aa18a29781c4db1d77ca5cb1dd4f68fb44 (patch)
tree9c3fbf6aec977663deaf766bbaaf5f5a8a41a15c /net/tipc/netlink_compat.c
parent361b1231801944ddecbd0e383420932633cac2d1 (diff)
parented4ffdfec26dfe1bb02435afd1e01f61426f7212 (diff)
Merge branch 'tipc-locking-fixes'
Ying Xue says: ==================== tipc: Fix missing RTNL lock protection during setting link properties At present it's unsafe to configure link properties through netlink as the entire setting process is not under RTNL lock protection. Now TIPC supports two different sets of netlink APIs at the same time, and they share the same set of backend functions to configure bearer, media and net properties. In order to solve the missing RTNL issue, we have to make the whole __tipc_nl_compat_doit() protected by RTNL, which means any function called within it cannot take RTNL any more. So in the series we first introduce the following new functions which doesn't hold RTNl lock: - __tipc_nl_bearer_disable() - __tipc_nl_bearer_enable() - __tipc_nl_bearer_set() - __tipc_nl_media_set() - __tipc_nl_net_set() Meanwhile, __tipc_nl_compat_doit() has been reconstructed to minimize the time of holding RTNL lock. Changes in v4: - Per suggestion of Kirill Tkhai, divided original big one patch into seven small ones so that they can be easily reviewed. Changes in v3: - Optimized return method of __tipc_nl_bearer_enable() regarding the comments from David M and Kirill Tkhai - Moved the allocations of memory in __tipc_nl_compat_doit() out of RTNL lock to minimize the time of holding RTNL lock according to the suggestion of Kirill Tkhai. Changes in v2: - The whole operation of setting bearer/media properties has been protected under RTNL, as per feedback from David M. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/netlink_compat.c')
-rw-r--r--net/tipc/netlink_compat.c43
1 files changed, 23 insertions, 20 deletions
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index e48f0b2c01b9..4492cda45566 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -285,10 +285,6 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
285 if (!trans_buf) 285 if (!trans_buf)
286 return -ENOMEM; 286 return -ENOMEM;
287 287
288 err = (*cmd->transcode)(cmd, trans_buf, msg);
289 if (err)
290 goto trans_out;
291
292 attrbuf = kmalloc((tipc_genl_family.maxattr + 1) * 288 attrbuf = kmalloc((tipc_genl_family.maxattr + 1) *
293 sizeof(struct nlattr *), GFP_KERNEL); 289 sizeof(struct nlattr *), GFP_KERNEL);
294 if (!attrbuf) { 290 if (!attrbuf) {
@@ -296,27 +292,34 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
296 goto trans_out; 292 goto trans_out;
297 } 293 }
298 294
299 err = nla_parse(attrbuf, tipc_genl_family.maxattr,
300 (const struct nlattr *)trans_buf->data,
301 trans_buf->len, NULL, NULL);
302 if (err)
303 goto parse_out;
304
305 doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 295 doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
306 if (!doit_buf) { 296 if (!doit_buf) {
307 err = -ENOMEM; 297 err = -ENOMEM;
308 goto parse_out; 298 goto attrbuf_out;
309 } 299 }
310 300
311 doit_buf->sk = msg->dst_sk;
312
313 memset(&info, 0, sizeof(info)); 301 memset(&info, 0, sizeof(info));
314 info.attrs = attrbuf; 302 info.attrs = attrbuf;
315 303
304 rtnl_lock();
305 err = (*cmd->transcode)(cmd, trans_buf, msg);
306 if (err)
307 goto doit_out;
308
309 err = nla_parse(attrbuf, tipc_genl_family.maxattr,
310 (const struct nlattr *)trans_buf->data,
311 trans_buf->len, NULL, NULL);
312 if (err)
313 goto doit_out;
314
315 doit_buf->sk = msg->dst_sk;
316
316 err = (*cmd->doit)(doit_buf, &info); 317 err = (*cmd->doit)(doit_buf, &info);
318doit_out:
319 rtnl_unlock();
317 320
318 kfree_skb(doit_buf); 321 kfree_skb(doit_buf);
319parse_out: 322attrbuf_out:
320 kfree(attrbuf); 323 kfree(attrbuf);
321trans_out: 324trans_out:
322 kfree_skb(trans_buf); 325 kfree_skb(trans_buf);
@@ -722,13 +725,13 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,
722 725
723 media = tipc_media_find(lc->name); 726 media = tipc_media_find(lc->name);
724 if (media) { 727 if (media) {
725 cmd->doit = &tipc_nl_media_set; 728 cmd->doit = &__tipc_nl_media_set;
726 return tipc_nl_compat_media_set(skb, msg); 729 return tipc_nl_compat_media_set(skb, msg);
727 } 730 }
728 731
729 bearer = tipc_bearer_find(msg->net, lc->name); 732 bearer = tipc_bearer_find(msg->net, lc->name);
730 if (bearer) { 733 if (bearer) {
731 cmd->doit = &tipc_nl_bearer_set; 734 cmd->doit = &__tipc_nl_bearer_set;
732 return tipc_nl_compat_bearer_set(skb, msg); 735 return tipc_nl_compat_bearer_set(skb, msg);
733 } 736 }
734 737
@@ -1089,12 +1092,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
1089 return tipc_nl_compat_dumpit(&dump, msg); 1092 return tipc_nl_compat_dumpit(&dump, msg);
1090 case TIPC_CMD_ENABLE_BEARER: 1093 case TIPC_CMD_ENABLE_BEARER:
1091 msg->req_type = TIPC_TLV_BEARER_CONFIG; 1094 msg->req_type = TIPC_TLV_BEARER_CONFIG;
1092 doit.doit = tipc_nl_bearer_enable; 1095 doit.doit = __tipc_nl_bearer_enable;
1093 doit.transcode = tipc_nl_compat_bearer_enable; 1096 doit.transcode = tipc_nl_compat_bearer_enable;
1094 return tipc_nl_compat_doit(&doit, msg); 1097 return tipc_nl_compat_doit(&doit, msg);
1095 case TIPC_CMD_DISABLE_BEARER: 1098 case TIPC_CMD_DISABLE_BEARER:
1096 msg->req_type = TIPC_TLV_BEARER_NAME; 1099 msg->req_type = TIPC_TLV_BEARER_NAME;
1097 doit.doit = tipc_nl_bearer_disable; 1100 doit.doit = __tipc_nl_bearer_disable;
1098 doit.transcode = tipc_nl_compat_bearer_disable; 1101 doit.transcode = tipc_nl_compat_bearer_disable;
1099 return tipc_nl_compat_doit(&doit, msg); 1102 return tipc_nl_compat_doit(&doit, msg);
1100 case TIPC_CMD_SHOW_LINK_STATS: 1103 case TIPC_CMD_SHOW_LINK_STATS:
@@ -1148,12 +1151,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
1148 return tipc_nl_compat_dumpit(&dump, msg); 1151 return tipc_nl_compat_dumpit(&dump, msg);
1149 case TIPC_CMD_SET_NODE_ADDR: 1152 case TIPC_CMD_SET_NODE_ADDR:
1150 msg->req_type = TIPC_TLV_NET_ADDR; 1153 msg->req_type = TIPC_TLV_NET_ADDR;
1151 doit.doit = tipc_nl_net_set; 1154 doit.doit = __tipc_nl_net_set;
1152 doit.transcode = tipc_nl_compat_net_set; 1155 doit.transcode = tipc_nl_compat_net_set;
1153 return tipc_nl_compat_doit(&doit, msg); 1156 return tipc_nl_compat_doit(&doit, msg);
1154 case TIPC_CMD_SET_NETID: 1157 case TIPC_CMD_SET_NETID:
1155 msg->req_type = TIPC_TLV_UNSIGNED; 1158 msg->req_type = TIPC_TLV_UNSIGNED;
1156 doit.doit = tipc_nl_net_set; 1159 doit.doit = __tipc_nl_net_set;
1157 doit.transcode = tipc_nl_compat_net_set; 1160 doit.transcode = tipc_nl_compat_net_set;
1158 return tipc_nl_compat_doit(&doit, msg); 1161 return tipc_nl_compat_doit(&doit, msg);
1159 case TIPC_CMD_GET_NETID: 1162 case TIPC_CMD_GET_NETID: