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>
This commit is contained in:
commit
080fe7aa18
@ -813,7 +813,7 @@ err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
|
||||
int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
char *name;
|
||||
@ -835,20 +835,27 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
|
||||
|
||||
rtnl_lock();
|
||||
bearer = tipc_bearer_find(net, name);
|
||||
if (!bearer) {
|
||||
rtnl_unlock();
|
||||
if (!bearer)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bearer_disable(net, bearer);
|
||||
rtnl_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
|
||||
int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
rtnl_lock();
|
||||
err = __tipc_nl_bearer_disable(skb, info);
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
char *bearer;
|
||||
@ -890,15 +897,18 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
|
||||
prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
|
||||
}
|
||||
|
||||
return tipc_enable_bearer(net, bearer, domain, prio, attrs);
|
||||
}
|
||||
|
||||
int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
rtnl_lock();
|
||||
err = tipc_enable_bearer(net, bearer, domain, prio, attrs);
|
||||
if (err) {
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
err = __tipc_nl_bearer_enable(skb, info);
|
||||
rtnl_unlock();
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
|
||||
@ -944,7 +954,7 @@ int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
|
||||
int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
char *name;
|
||||
@ -965,22 +975,17 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
|
||||
return -EINVAL;
|
||||
name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
|
||||
|
||||
rtnl_lock();
|
||||
b = tipc_bearer_find(net, name);
|
||||
if (!b) {
|
||||
rtnl_unlock();
|
||||
if (!b)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (attrs[TIPC_NLA_BEARER_PROP]) {
|
||||
struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
|
||||
|
||||
err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
|
||||
props);
|
||||
if (err) {
|
||||
rtnl_unlock();
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (props[TIPC_NLA_PROP_TOL])
|
||||
b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
|
||||
@ -989,11 +994,21 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
|
||||
if (props[TIPC_NLA_PROP_WIN])
|
||||
b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
rtnl_lock();
|
||||
err = __tipc_nl_bearer_set(skb, info);
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
|
||||
struct tipc_media *media, int nlflags)
|
||||
{
|
||||
@ -1115,7 +1130,7 @@ err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
|
||||
int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
char *name;
|
||||
@ -1133,22 +1148,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
|
||||
return -EINVAL;
|
||||
name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]);
|
||||
|
||||
rtnl_lock();
|
||||
m = tipc_media_find(name);
|
||||
if (!m) {
|
||||
rtnl_unlock();
|
||||
if (!m)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (attrs[TIPC_NLA_MEDIA_PROP]) {
|
||||
struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
|
||||
|
||||
err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP],
|
||||
props);
|
||||
if (err) {
|
||||
rtnl_unlock();
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (props[TIPC_NLA_PROP_TOL])
|
||||
m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
|
||||
@ -1157,7 +1167,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
|
||||
if (props[TIPC_NLA_PROP_WIN])
|
||||
m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
rtnl_lock();
|
||||
err = __tipc_nl_media_set(skb, info);
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -188,15 +188,19 @@ extern struct tipc_media udp_media_info;
|
||||
#endif
|
||||
|
||||
int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
|
||||
int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
|
||||
int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
|
||||
int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
|
||||
int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info);
|
||||
int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
|
||||
int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
|
||||
int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info);
|
||||
int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
|
||||
int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
int tipc_media_set_priority(const char *name, u32 new_value);
|
||||
int tipc_media_set_window(const char *name, u32 new_value);
|
||||
|
@ -200,7 +200,7 @@ out:
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
|
||||
int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct tipc_net *tn = net_generic(net, tipc_net_id);
|
||||
@ -241,10 +241,19 @@ int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!tipc_addr_node_valid(addr))
|
||||
return -EINVAL;
|
||||
|
||||
rtnl_lock();
|
||||
tipc_net_start(net, addr);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
rtnl_lock();
|
||||
err = __tipc_nl_net_set(skb, info);
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -47,5 +47,6 @@ void tipc_net_stop(struct net *net);
|
||||
|
||||
int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
|
||||
int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
#endif
|
||||
|
@ -285,10 +285,6 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
|
||||
if (!trans_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
err = (*cmd->transcode)(cmd, trans_buf, msg);
|
||||
if (err)
|
||||
goto trans_out;
|
||||
|
||||
attrbuf = kmalloc((tipc_genl_family.maxattr + 1) *
|
||||
sizeof(struct nlattr *), GFP_KERNEL);
|
||||
if (!attrbuf) {
|
||||
@ -296,27 +292,34 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
|
||||
goto trans_out;
|
||||
}
|
||||
|
||||
err = nla_parse(attrbuf, tipc_genl_family.maxattr,
|
||||
(const struct nlattr *)trans_buf->data,
|
||||
trans_buf->len, NULL, NULL);
|
||||
if (err)
|
||||
goto parse_out;
|
||||
|
||||
doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||
if (!doit_buf) {
|
||||
err = -ENOMEM;
|
||||
goto parse_out;
|
||||
goto attrbuf_out;
|
||||
}
|
||||
|
||||
doit_buf->sk = msg->dst_sk;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.attrs = attrbuf;
|
||||
|
||||
rtnl_lock();
|
||||
err = (*cmd->transcode)(cmd, trans_buf, msg);
|
||||
if (err)
|
||||
goto doit_out;
|
||||
|
||||
err = nla_parse(attrbuf, tipc_genl_family.maxattr,
|
||||
(const struct nlattr *)trans_buf->data,
|
||||
trans_buf->len, NULL, NULL);
|
||||
if (err)
|
||||
goto doit_out;
|
||||
|
||||
doit_buf->sk = msg->dst_sk;
|
||||
|
||||
err = (*cmd->doit)(doit_buf, &info);
|
||||
doit_out:
|
||||
rtnl_unlock();
|
||||
|
||||
kfree_skb(doit_buf);
|
||||
parse_out:
|
||||
attrbuf_out:
|
||||
kfree(attrbuf);
|
||||
trans_out:
|
||||
kfree_skb(trans_buf);
|
||||
@ -722,13 +725,13 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,
|
||||
|
||||
media = tipc_media_find(lc->name);
|
||||
if (media) {
|
||||
cmd->doit = &tipc_nl_media_set;
|
||||
cmd->doit = &__tipc_nl_media_set;
|
||||
return tipc_nl_compat_media_set(skb, msg);
|
||||
}
|
||||
|
||||
bearer = tipc_bearer_find(msg->net, lc->name);
|
||||
if (bearer) {
|
||||
cmd->doit = &tipc_nl_bearer_set;
|
||||
cmd->doit = &__tipc_nl_bearer_set;
|
||||
return tipc_nl_compat_bearer_set(skb, msg);
|
||||
}
|
||||
|
||||
@ -1089,12 +1092,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
|
||||
return tipc_nl_compat_dumpit(&dump, msg);
|
||||
case TIPC_CMD_ENABLE_BEARER:
|
||||
msg->req_type = TIPC_TLV_BEARER_CONFIG;
|
||||
doit.doit = tipc_nl_bearer_enable;
|
||||
doit.doit = __tipc_nl_bearer_enable;
|
||||
doit.transcode = tipc_nl_compat_bearer_enable;
|
||||
return tipc_nl_compat_doit(&doit, msg);
|
||||
case TIPC_CMD_DISABLE_BEARER:
|
||||
msg->req_type = TIPC_TLV_BEARER_NAME;
|
||||
doit.doit = tipc_nl_bearer_disable;
|
||||
doit.doit = __tipc_nl_bearer_disable;
|
||||
doit.transcode = tipc_nl_compat_bearer_disable;
|
||||
return tipc_nl_compat_doit(&doit, msg);
|
||||
case TIPC_CMD_SHOW_LINK_STATS:
|
||||
@ -1148,12 +1151,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
|
||||
return tipc_nl_compat_dumpit(&dump, msg);
|
||||
case TIPC_CMD_SET_NODE_ADDR:
|
||||
msg->req_type = TIPC_TLV_NET_ADDR;
|
||||
doit.doit = tipc_nl_net_set;
|
||||
doit.doit = __tipc_nl_net_set;
|
||||
doit.transcode = tipc_nl_compat_net_set;
|
||||
return tipc_nl_compat_doit(&doit, msg);
|
||||
case TIPC_CMD_SET_NETID:
|
||||
msg->req_type = TIPC_TLV_UNSIGNED;
|
||||
doit.doit = tipc_nl_net_set;
|
||||
doit.doit = __tipc_nl_net_set;
|
||||
doit.transcode = tipc_nl_compat_net_set;
|
||||
return tipc_nl_compat_doit(&doit, msg);
|
||||
case TIPC_CMD_GET_NETID:
|
||||
|
Loading…
Reference in New Issue
Block a user