diff options
author | Gao feng <gaofeng@cn.fujitsu.com> | 2012-10-04 16:15:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-10-07 00:30:56 -0400 |
commit | 6dc878a8ca39e93f70c42f3dd7260bde10c1e0f1 (patch) | |
tree | 2549dc75d29ea1975611775b05921482caf75c04 /net/netlink/af_netlink.c | |
parent | ed5062ddaa71e9f8b2b3aacc264428ce6da93d9e (diff) |
netlink: add reference of module in netlink_dump_start
I get a panic when I use ss -a and rmmod inet_diag at the
same time.
It's because netlink_dump uses inet_diag_dump which belongs to module
inet_diag.
I search the codes and find many modules have the same problem. We
need to add a reference to the module which the cb->dump belongs to.
Thanks for all help from Stephen,Jan,Eric,Steffen and Pablo.
Change From v3:
change netlink_dump_start to inline,suggestion from Pablo and
Eric.
Change From v2:
delete netlink_dump_done,and call module_put in netlink_dump
and netlink_sock_destruct.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r-- | net/netlink/af_netlink.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 0f2e3ad69c47..01e944a017a4 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -169,6 +169,8 @@ static void netlink_sock_destruct(struct sock *sk) | |||
169 | if (nlk->cb) { | 169 | if (nlk->cb) { |
170 | if (nlk->cb->done) | 170 | if (nlk->cb->done) |
171 | nlk->cb->done(nlk->cb); | 171 | nlk->cb->done(nlk->cb); |
172 | |||
173 | module_put(nlk->cb->module); | ||
172 | netlink_destroy_callback(nlk->cb); | 174 | netlink_destroy_callback(nlk->cb); |
173 | } | 175 | } |
174 | 176 | ||
@@ -1758,6 +1760,7 @@ static int netlink_dump(struct sock *sk) | |||
1758 | nlk->cb = NULL; | 1760 | nlk->cb = NULL; |
1759 | mutex_unlock(nlk->cb_mutex); | 1761 | mutex_unlock(nlk->cb_mutex); |
1760 | 1762 | ||
1763 | module_put(cb->module); | ||
1761 | netlink_consume_callback(cb); | 1764 | netlink_consume_callback(cb); |
1762 | return 0; | 1765 | return 0; |
1763 | 1766 | ||
@@ -1767,9 +1770,9 @@ errout_skb: | |||
1767 | return err; | 1770 | return err; |
1768 | } | 1771 | } |
1769 | 1772 | ||
1770 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | 1773 | int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, |
1771 | const struct nlmsghdr *nlh, | 1774 | const struct nlmsghdr *nlh, |
1772 | struct netlink_dump_control *control) | 1775 | struct netlink_dump_control *control) |
1773 | { | 1776 | { |
1774 | struct netlink_callback *cb; | 1777 | struct netlink_callback *cb; |
1775 | struct sock *sk; | 1778 | struct sock *sk; |
@@ -1784,6 +1787,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1784 | cb->done = control->done; | 1787 | cb->done = control->done; |
1785 | cb->nlh = nlh; | 1788 | cb->nlh = nlh; |
1786 | cb->data = control->data; | 1789 | cb->data = control->data; |
1790 | cb->module = control->module; | ||
1787 | cb->min_dump_alloc = control->min_dump_alloc; | 1791 | cb->min_dump_alloc = control->min_dump_alloc; |
1788 | atomic_inc(&skb->users); | 1792 | atomic_inc(&skb->users); |
1789 | cb->skb = skb; | 1793 | cb->skb = skb; |
@@ -1794,19 +1798,28 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1794 | return -ECONNREFUSED; | 1798 | return -ECONNREFUSED; |
1795 | } | 1799 | } |
1796 | nlk = nlk_sk(sk); | 1800 | nlk = nlk_sk(sk); |
1797 | /* A dump is in progress... */ | 1801 | |
1798 | mutex_lock(nlk->cb_mutex); | 1802 | mutex_lock(nlk->cb_mutex); |
1803 | /* A dump is in progress... */ | ||
1799 | if (nlk->cb) { | 1804 | if (nlk->cb) { |
1800 | mutex_unlock(nlk->cb_mutex); | 1805 | mutex_unlock(nlk->cb_mutex); |
1801 | netlink_destroy_callback(cb); | 1806 | netlink_destroy_callback(cb); |
1802 | sock_put(sk); | 1807 | ret = -EBUSY; |
1803 | return -EBUSY; | 1808 | goto out; |
1804 | } | 1809 | } |
1810 | /* add reference of module which cb->dump belongs to */ | ||
1811 | if (!try_module_get(cb->module)) { | ||
1812 | mutex_unlock(nlk->cb_mutex); | ||
1813 | netlink_destroy_callback(cb); | ||
1814 | ret = -EPROTONOSUPPORT; | ||
1815 | goto out; | ||
1816 | } | ||
1817 | |||
1805 | nlk->cb = cb; | 1818 | nlk->cb = cb; |
1806 | mutex_unlock(nlk->cb_mutex); | 1819 | mutex_unlock(nlk->cb_mutex); |
1807 | 1820 | ||
1808 | ret = netlink_dump(sk); | 1821 | ret = netlink_dump(sk); |
1809 | 1822 | out: | |
1810 | sock_put(sk); | 1823 | sock_put(sk); |
1811 | 1824 | ||
1812 | if (ret) | 1825 | if (ret) |
@@ -1817,7 +1830,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1817 | */ | 1830 | */ |
1818 | return -EINTR; | 1831 | return -EINTR; |
1819 | } | 1832 | } |
1820 | EXPORT_SYMBOL(netlink_dump_start); | 1833 | EXPORT_SYMBOL(__netlink_dump_start); |
1821 | 1834 | ||
1822 | void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | 1835 | void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) |
1823 | { | 1836 | { |