|
@@ -169,6 +169,8 @@ static void netlink_sock_destruct(struct sock *sk)
|
|
|
if (nlk->cb) {
|
|
|
if (nlk->cb->done)
|
|
|
nlk->cb->done(nlk->cb);
|
|
|
+
|
|
|
+ module_put(nlk->cb->module);
|
|
|
netlink_destroy_callback(nlk->cb);
|
|
|
}
|
|
|
|
|
@@ -1758,6 +1760,7 @@ static int netlink_dump(struct sock *sk)
|
|
|
nlk->cb = NULL;
|
|
|
mutex_unlock(nlk->cb_mutex);
|
|
|
|
|
|
+ module_put(cb->module);
|
|
|
netlink_consume_callback(cb);
|
|
|
return 0;
|
|
|
|
|
@@ -1767,9 +1770,9 @@ errout_skb:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|
|
- const struct nlmsghdr *nlh,
|
|
|
- struct netlink_dump_control *control)
|
|
|
+int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|
|
+ const struct nlmsghdr *nlh,
|
|
|
+ struct netlink_dump_control *control)
|
|
|
{
|
|
|
struct netlink_callback *cb;
|
|
|
struct sock *sk;
|
|
@@ -1784,6 +1787,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|
|
cb->done = control->done;
|
|
|
cb->nlh = nlh;
|
|
|
cb->data = control->data;
|
|
|
+ cb->module = control->module;
|
|
|
cb->min_dump_alloc = control->min_dump_alloc;
|
|
|
atomic_inc(&skb->users);
|
|
|
cb->skb = skb;
|
|
@@ -1794,19 +1798,28 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|
|
return -ECONNREFUSED;
|
|
|
}
|
|
|
nlk = nlk_sk(sk);
|
|
|
- /* A dump is in progress... */
|
|
|
+
|
|
|
mutex_lock(nlk->cb_mutex);
|
|
|
+ /* A dump is in progress... */
|
|
|
if (nlk->cb) {
|
|
|
mutex_unlock(nlk->cb_mutex);
|
|
|
netlink_destroy_callback(cb);
|
|
|
- sock_put(sk);
|
|
|
- return -EBUSY;
|
|
|
+ ret = -EBUSY;
|
|
|
+ goto out;
|
|
|
}
|
|
|
+ /* add reference of module which cb->dump belongs to */
|
|
|
+ if (!try_module_get(cb->module)) {
|
|
|
+ mutex_unlock(nlk->cb_mutex);
|
|
|
+ netlink_destroy_callback(cb);
|
|
|
+ ret = -EPROTONOSUPPORT;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
nlk->cb = cb;
|
|
|
mutex_unlock(nlk->cb_mutex);
|
|
|
|
|
|
ret = netlink_dump(sk);
|
|
|
-
|
|
|
+out:
|
|
|
sock_put(sk);
|
|
|
|
|
|
if (ret)
|
|
@@ -1817,7 +1830,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|
|
*/
|
|
|
return -EINTR;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(netlink_dump_start);
|
|
|
+EXPORT_SYMBOL(__netlink_dump_start);
|
|
|
|
|
|
void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
|
|
|
{
|