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>
This commit is contained in:
parent
ed5062ddaa
commit
6dc878a8ca
2 changed files with 37 additions and 12 deletions
|
@ -245,6 +245,8 @@ struct netlink_callback {
|
||||||
struct netlink_callback *cb);
|
struct netlink_callback *cb);
|
||||||
int (*done)(struct netlink_callback *cb);
|
int (*done)(struct netlink_callback *cb);
|
||||||
void *data;
|
void *data;
|
||||||
|
/* the module that dump function belong to */
|
||||||
|
struct module *module;
|
||||||
u16 family;
|
u16 family;
|
||||||
u16 min_dump_alloc;
|
u16 min_dump_alloc;
|
||||||
unsigned int prev_seq, seq;
|
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
|
||||||
|
|
||||||
struct netlink_dump_control {
|
struct netlink_dump_control {
|
||||||
int (*dump)(struct sk_buff *skb, struct netlink_callback *);
|
int (*dump)(struct sk_buff *skb, struct netlink_callback *);
|
||||||
int (*done)(struct netlink_callback*);
|
int (*done)(struct netlink_callback *);
|
||||||
void *data;
|
void *data;
|
||||||
|
struct module *module;
|
||||||
u16 min_dump_alloc;
|
u16 min_dump_alloc;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
extern int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
struct netlink_dump_control *control);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,8 @@ static void netlink_sock_destruct(struct sock *sk)
|
||||||
if (nlk->cb) {
|
if (nlk->cb) {
|
||||||
if (nlk->cb->done)
|
if (nlk->cb->done)
|
||||||
nlk->cb->done(nlk->cb);
|
nlk->cb->done(nlk->cb);
|
||||||
|
|
||||||
|
module_put(nlk->cb->module);
|
||||||
netlink_destroy_callback(nlk->cb);
|
netlink_destroy_callback(nlk->cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1758,6 +1760,7 @@ static int netlink_dump(struct sock *sk)
|
||||||
nlk->cb = NULL;
|
nlk->cb = NULL;
|
||||||
mutex_unlock(nlk->cb_mutex);
|
mutex_unlock(nlk->cb_mutex);
|
||||||
|
|
||||||
|
module_put(cb->module);
|
||||||
netlink_consume_callback(cb);
|
netlink_consume_callback(cb);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1767,9 +1770,9 @@ static int netlink_dump(struct sock *sk)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
struct netlink_dump_control *control)
|
struct netlink_dump_control *control)
|
||||||
{
|
{
|
||||||
struct netlink_callback *cb;
|
struct netlink_callback *cb;
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
|
@ -1784,6 +1787,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||||
cb->done = control->done;
|
cb->done = control->done;
|
||||||
cb->nlh = nlh;
|
cb->nlh = nlh;
|
||||||
cb->data = control->data;
|
cb->data = control->data;
|
||||||
|
cb->module = control->module;
|
||||||
cb->min_dump_alloc = control->min_dump_alloc;
|
cb->min_dump_alloc = control->min_dump_alloc;
|
||||||
atomic_inc(&skb->users);
|
atomic_inc(&skb->users);
|
||||||
cb->skb = skb;
|
cb->skb = skb;
|
||||||
|
@ -1794,19 +1798,28 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||||
return -ECONNREFUSED;
|
return -ECONNREFUSED;
|
||||||
}
|
}
|
||||||
nlk = nlk_sk(sk);
|
nlk = nlk_sk(sk);
|
||||||
/* A dump is in progress... */
|
|
||||||
mutex_lock(nlk->cb_mutex);
|
mutex_lock(nlk->cb_mutex);
|
||||||
|
/* A dump is in progress... */
|
||||||
if (nlk->cb) {
|
if (nlk->cb) {
|
||||||
mutex_unlock(nlk->cb_mutex);
|
mutex_unlock(nlk->cb_mutex);
|
||||||
netlink_destroy_callback(cb);
|
netlink_destroy_callback(cb);
|
||||||
sock_put(sk);
|
ret = -EBUSY;
|
||||||
return -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;
|
nlk->cb = cb;
|
||||||
mutex_unlock(nlk->cb_mutex);
|
mutex_unlock(nlk->cb_mutex);
|
||||||
|
|
||||||
ret = netlink_dump(sk);
|
ret = netlink_dump(sk);
|
||||||
|
out:
|
||||||
sock_put(sk);
|
sock_put(sk);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -1817,7 +1830,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||||
*/
|
*/
|
||||||
return -EINTR;
|
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)
|
void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue