diff options
-rw-r--r-- | include/linux/netlink.h | 20 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 29 |
2 files changed, 37 insertions, 12 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index f80c56ac4d82..6d3af05c107c 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h | |||
@@ -245,6 +245,8 @@ struct netlink_callback { | |||
245 | struct netlink_callback *cb); | 245 | struct netlink_callback *cb); |
246 | int (*done)(struct netlink_callback *cb); | 246 | int (*done)(struct netlink_callback *cb); |
247 | void *data; | 247 | void *data; |
248 | /* the module that dump function belong to */ | ||
249 | struct module *module; | ||
248 | u16 family; | 250 | u16 family; |
249 | u16 min_dump_alloc; | 251 | u16 min_dump_alloc; |
250 | unsigned int prev_seq, seq; | 252 | unsigned int prev_seq, seq; |
@@ -262,14 +264,24 @@ __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int fla | |||
262 | 264 | ||
263 | struct netlink_dump_control { | 265 | struct netlink_dump_control { |
264 | int (*dump)(struct sk_buff *skb, struct netlink_callback *); | 266 | int (*dump)(struct sk_buff *skb, struct netlink_callback *); |
265 | int (*done)(struct netlink_callback*); | 267 | int (*done)(struct netlink_callback *); |
266 | void *data; | 268 | void *data; |
269 | struct module *module; | ||
267 | u16 min_dump_alloc; | 270 | u16 min_dump_alloc; |
268 | }; | 271 | }; |
269 | 272 | ||
270 | extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | 273 | extern int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, |
271 | const struct nlmsghdr *nlh, | 274 | const struct nlmsghdr *nlh, |
272 | struct netlink_dump_control *control); | 275 | struct netlink_dump_control *control); |
276 | static inline int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | ||
277 | const struct nlmsghdr *nlh, | ||
278 | struct netlink_dump_control *control) | ||
279 | { | ||
280 | if (!control->module) | ||
281 | control->module = THIS_MODULE; | ||
282 | |||
283 | return __netlink_dump_start(ssk, skb, nlh, control); | ||
284 | } | ||
273 | 285 | ||
274 | #endif /* __KERNEL__ */ | 286 | #endif /* __KERNEL__ */ |
275 | 287 | ||
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 | { |