ipvs: call rtnl_lock early
When the sync damon is started we need to hold rtnl
lock while calling ip_mc_join_group. Currently, we have
a wrong locking order because the correct one is
rtnl_lock->__ip_vs_mutex. It is implied from the usage
of __ip_vs_mutex in ip_vs_dst_event() which is called
under rtnl lock during NETDEV_* notifications.
Fix the problem by calling rtnl_lock early only for the
start_sync_thread call. As a bonus this fixes the usage
__dev_get_by_name which was not called under rtnl lock.
This patch actually extends and depends on commit 54ff9ef36b
("ipv4, ipv6: kill ip_mc_{join, leave}_group and
ipv6_sock_mc_{join, drop}").
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
This commit is contained in:
parent
eefa32d3f3
commit
e0b26cc997
|
@ -2335,13 +2335,18 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
|
||||||
cmd == IP_VS_SO_SET_STOPDAEMON) {
|
cmd == IP_VS_SO_SET_STOPDAEMON) {
|
||||||
struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
|
struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
|
||||||
|
|
||||||
mutex_lock(&ipvs->sync_mutex);
|
if (cmd == IP_VS_SO_SET_STARTDAEMON) {
|
||||||
if (cmd == IP_VS_SO_SET_STARTDAEMON)
|
rtnl_lock();
|
||||||
|
mutex_lock(&ipvs->sync_mutex);
|
||||||
ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
|
ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
|
||||||
dm->syncid);
|
dm->syncid);
|
||||||
else
|
mutex_unlock(&ipvs->sync_mutex);
|
||||||
|
rtnl_unlock();
|
||||||
|
} else {
|
||||||
|
mutex_lock(&ipvs->sync_mutex);
|
||||||
ret = stop_sync_thread(net, dm->state);
|
ret = stop_sync_thread(net, dm->state);
|
||||||
mutex_unlock(&ipvs->sync_mutex);
|
mutex_unlock(&ipvs->sync_mutex);
|
||||||
|
}
|
||||||
goto out_dec;
|
goto out_dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3342,6 +3347,9 @@ nla_put_failure:
|
||||||
|
|
||||||
static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs)
|
static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs)
|
||||||
{
|
{
|
||||||
|
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!(attrs[IPVS_DAEMON_ATTR_STATE] &&
|
if (!(attrs[IPVS_DAEMON_ATTR_STATE] &&
|
||||||
attrs[IPVS_DAEMON_ATTR_MCAST_IFN] &&
|
attrs[IPVS_DAEMON_ATTR_MCAST_IFN] &&
|
||||||
attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
|
attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
|
||||||
|
@ -3353,19 +3361,30 @@ static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs)
|
||||||
if (net_ipvs(net)->mixed_address_family_dests > 0)
|
if (net_ipvs(net)->mixed_address_family_dests > 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return start_sync_thread(net,
|
rtnl_lock();
|
||||||
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
|
mutex_lock(&ipvs->sync_mutex);
|
||||||
nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
|
ret = start_sync_thread(net,
|
||||||
nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
|
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
|
||||||
|
nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
|
||||||
|
nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
|
||||||
|
mutex_unlock(&ipvs->sync_mutex);
|
||||||
|
rtnl_unlock();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ip_vs_genl_del_daemon(struct net *net, struct nlattr **attrs)
|
static int ip_vs_genl_del_daemon(struct net *net, struct nlattr **attrs)
|
||||||
{
|
{
|
||||||
|
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!attrs[IPVS_DAEMON_ATTR_STATE])
|
if (!attrs[IPVS_DAEMON_ATTR_STATE])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return stop_sync_thread(net,
|
mutex_lock(&ipvs->sync_mutex);
|
||||||
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
|
ret = stop_sync_thread(net,
|
||||||
|
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
|
||||||
|
mutex_unlock(&ipvs->sync_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
|
static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
|
||||||
|
@ -3389,7 +3408,7 @@ static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
|
||||||
|
|
||||||
static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
|
static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
int ret = 0, cmd;
|
int ret = -EINVAL, cmd;
|
||||||
struct net *net;
|
struct net *net;
|
||||||
struct netns_ipvs *ipvs;
|
struct netns_ipvs *ipvs;
|
||||||
|
|
||||||
|
@ -3400,22 +3419,19 @@ static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (cmd == IPVS_CMD_NEW_DAEMON || cmd == IPVS_CMD_DEL_DAEMON) {
|
if (cmd == IPVS_CMD_NEW_DAEMON || cmd == IPVS_CMD_DEL_DAEMON) {
|
||||||
struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
|
struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
|
||||||
|
|
||||||
mutex_lock(&ipvs->sync_mutex);
|
|
||||||
if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
|
if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
|
||||||
nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
|
nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
|
||||||
info->attrs[IPVS_CMD_ATTR_DAEMON],
|
info->attrs[IPVS_CMD_ATTR_DAEMON],
|
||||||
ip_vs_daemon_policy)) {
|
ip_vs_daemon_policy))
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd == IPVS_CMD_NEW_DAEMON)
|
if (cmd == IPVS_CMD_NEW_DAEMON)
|
||||||
ret = ip_vs_genl_new_daemon(net, daemon_attrs);
|
ret = ip_vs_genl_new_daemon(net, daemon_attrs);
|
||||||
else
|
else
|
||||||
ret = ip_vs_genl_del_daemon(net, daemon_attrs);
|
ret = ip_vs_genl_del_daemon(net, daemon_attrs);
|
||||||
out:
|
|
||||||
mutex_unlock(&ipvs->sync_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1405,11 +1405,9 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
|
||||||
|
|
||||||
mreq.imr_ifindex = dev->ifindex;
|
mreq.imr_ifindex = dev->ifindex;
|
||||||
|
|
||||||
rtnl_lock();
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
ret = ip_mc_join_group(sk, &mreq);
|
ret = ip_mc_join_group(sk, &mreq);
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
rtnl_unlock();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue