diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-05-25 03:34:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-25 17:55:32 -0400 |
commit | 2907c35ff64708065e5a7fd54e8ded8263eb3074 (patch) | |
tree | b5046b08b0b4b13c45a2fffef4ad3218c9db07d8 | |
parent | 1dcb14d9e874d12bab9ceeba776b742f1682b0a6 (diff) |
net: hold rtnl again in dump callbacks
Commit e67f88dd12f6 (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>
-rw-r--r-- | net/core/fib_rules.c | 1 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 9 |
2 files changed, 8 insertions, 2 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 3911586e12e4..008dc70b064b 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -602,6 +602,7 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb, | |||
602 | skip: | 602 | skip: |
603 | idx++; | 603 | idx++; |
604 | } | 604 | } |
605 | rcu_read_unlock(); | ||
605 | cb->args[1] = idx; | 606 | cb->args[1] = idx; |
606 | rules_ops_put(ops); | 607 | rules_ops_put(ops); |
607 | 608 | ||
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d1644e317e70..2d56cb9b0b94 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -850,6 +850,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
850 | struct nlattr *attr, *af_spec; | 850 | struct nlattr *attr, *af_spec; |
851 | struct rtnl_af_ops *af_ops; | 851 | struct rtnl_af_ops *af_ops; |
852 | 852 | ||
853 | ASSERT_RTNL(); | ||
853 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); | 854 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); |
854 | if (nlh == NULL) | 855 | if (nlh == NULL) |
855 | return -EMSGSIZE; | 856 | return -EMSGSIZE; |
@@ -1876,6 +1877,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1876 | int min_len; | 1877 | int min_len; |
1877 | int family; | 1878 | int family; |
1878 | int type; | 1879 | int type; |
1880 | int err; | ||
1879 | 1881 | ||
1880 | type = nlh->nlmsg_type; | 1882 | type = nlh->nlmsg_type; |
1881 | if (type > RTM_MAX) | 1883 | if (type > RTM_MAX) |
@@ -1902,8 +1904,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1902 | if (dumpit == NULL) | 1904 | if (dumpit == NULL) |
1903 | return -EOPNOTSUPP; | 1905 | return -EOPNOTSUPP; |
1904 | 1906 | ||
1907 | __rtnl_unlock(); | ||
1905 | rtnl = net->rtnl; | 1908 | rtnl = net->rtnl; |
1906 | return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); | 1909 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); |
1910 | rtnl_lock(); | ||
1911 | return err; | ||
1907 | } | 1912 | } |
1908 | 1913 | ||
1909 | memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); | 1914 | memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); |
@@ -1975,7 +1980,7 @@ static int __net_init rtnetlink_net_init(struct net *net) | |||
1975 | { | 1980 | { |
1976 | struct sock *sk; | 1981 | struct sock *sk; |
1977 | sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, | 1982 | sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, |
1978 | rtnetlink_rcv, NULL, THIS_MODULE); | 1983 | rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); |
1979 | if (!sk) | 1984 | if (!sk) |
1980 | return -ENOMEM; | 1985 | return -ENOMEM; |
1981 | net->rtnl = sk; | 1986 | net->rtnl = sk; |