mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
netlink: add reference of module in netlink_dump_start
[ Upstream commit 6dc878a8ca
]
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
f0dc514c8a
commit
70f7f1c70a
2 changed files with 38 additions and 12 deletions
|
@ -153,6 +153,7 @@ struct nlattr {
|
|||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
struct net;
|
||||
|
||||
|
@ -226,6 +227,8 @@ struct netlink_callback {
|
|||
struct netlink_callback *cb);
|
||||
int (*done)(struct netlink_callback *cb);
|
||||
void *data;
|
||||
/* the module that dump function belong to */
|
||||
struct module *module;
|
||||
u16 family;
|
||||
u16 min_dump_alloc;
|
||||
unsigned int prev_seq, seq;
|
||||
|
@ -251,14 +254,24 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
|
|||
|
||||
struct netlink_dump_control {
|
||||
int (*dump)(struct sk_buff *skb, struct netlink_callback *);
|
||||
int (*done)(struct netlink_callback*);
|
||||
int (*done)(struct netlink_callback *);
|
||||
void *data;
|
||||
struct module *module;
|
||||
u16 min_dump_alloc;
|
||||
};
|
||||
|
||||
extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
struct netlink_dump_control *control);
|
||||
extern int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
struct netlink_dump_control *control);
|
||||
static inline int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
struct netlink_dump_control *control)
|
||||
{
|
||||
if (!control->module)
|
||||
control->module = THIS_MODULE;
|
||||
|
||||
return __netlink_dump_start(ssk, skb, nlh, control);
|
||||
}
|
||||
|
||||
|
||||
#define NL_NONROOT_RECV 0x1
|
||||
|
|
|
@ -156,6 +156,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);
|
||||
}
|
||||
|
||||
|
@ -1728,6 +1730,7 @@ static int netlink_dump(struct sock *sk)
|
|||
nlk->cb = NULL;
|
||||
mutex_unlock(nlk->cb_mutex);
|
||||
|
||||
module_put(cb->module);
|
||||
netlink_destroy_callback(cb);
|
||||
return 0;
|
||||
|
||||
|
@ -1737,9 +1740,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;
|
||||
|
@ -1754,6 +1757,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;
|
||||
|
@ -1764,19 +1768,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)
|
||||
|
@ -1787,7 +1800,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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue