dect
/
linux-2.6
Archived
13
0
Fork 0

net: hold rtnl again in dump callbacks

Commit e67f88dd12 (dont hold rtnl mutex during netlink dump callbacks)
missed fact that rtnl_fill_ifinfo() must be called with rtnl held.

Because of possible deadlocks between two mutexes (cb_mutex and rtnl),
its not easy to solve this problem, so revert this part of the patch.

It also forgot one rcu_read_unlock() in FIB dump_rules()

Add one ASSERT_RTNL() in rtnl_fill_ifinfo() to remind us the rule.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Patrick McHardy <kaber@trash.net>
CC: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2011-05-25 07:34:04 +00:00 committed by David S. Miller
parent 1dcb14d9e8
commit 2907c35ff6
2 changed files with 8 additions and 2 deletions

View File

@ -602,6 +602,7 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
skip: skip:
idx++; idx++;
} }
rcu_read_unlock();
cb->args[1] = idx; cb->args[1] = idx;
rules_ops_put(ops); rules_ops_put(ops);

View File

@ -850,6 +850,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
struct nlattr *attr, *af_spec; struct nlattr *attr, *af_spec;
struct rtnl_af_ops *af_ops; struct rtnl_af_ops *af_ops;
ASSERT_RTNL();
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
if (nlh == NULL) if (nlh == NULL)
return -EMSGSIZE; return -EMSGSIZE;
@ -1876,6 +1877,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
int min_len; int min_len;
int family; int family;
int type; int type;
int err;
type = nlh->nlmsg_type; type = nlh->nlmsg_type;
if (type > RTM_MAX) if (type > RTM_MAX)
@ -1902,8 +1904,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (dumpit == NULL) if (dumpit == NULL)
return -EOPNOTSUPP; return -EOPNOTSUPP;
__rtnl_unlock();
rtnl = net->rtnl; rtnl = net->rtnl;
return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
rtnl_lock();
return err;
} }
memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
@ -1975,7 +1980,7 @@ static int __net_init rtnetlink_net_init(struct net *net)
{ {
struct sock *sk; struct sock *sk;
sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
rtnetlink_rcv, NULL, THIS_MODULE); rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
if (!sk) if (!sk)
return -ENOMEM; return -ENOMEM;
net->rtnl = sk; net->rtnl = sk;