[patch v3 01/11] netlink: add reference of module in netlink_dump_start
Subsystems:
networking [general] , the rest
STALE5119d
11 messages,
3 authors,
2012-10-05 · open the first message on its own page
I get a panic when I use ss -a and rmmod inet_diag at the
same time.
it's because netlink_dump use inet_diag_dump witch function
belongs to module inet_diag.
I search the codes and find many modules have the same problem.
We need add reference of the module witch the cb->dump belongs
to.
Thanks for all help from Stephen,Jan,Eric,Steffen and Pablo.
Change From v2:
delete netlink_dump_done,and call module_put in netlink_dump
and netlink_sock_destruct.
Signed-off-by: Gao feng <redacted>
---
include/linux/netlink.h | 5 ++++-
net/netlink/af_netlink.c | 21 +++++++++++++++++----
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index f80c56a..bf4e501 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h @@ -245,6 +245,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 ; @@ -262,8 +264,9 @@ __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int fla
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 ;
};
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 0f2e3ad..0905dfb 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c @@ -169,6 +169,7 @@ 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 );
}
@@ -1755,6 +1756,8 @@ static int netlink_dump(struct sock *sk)
if ( cb -> done )
cb -> done ( cb );
+
+ module_put ( cb -> module );
nlk -> cb = NULL ;
mutex_unlock ( nlk -> cb_mutex );
@@ -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 witch cb->dump belong 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 ) --
1.7.7.6
set netlink_dump_control.module to avoid panic.
Signed-off-by: Gao feng <redacted>
---
net/netfilter/nf_conntrack_netlink.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 7bbfb3d..20af287 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c @@ -1022,6 +1022,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct netlink_dump_control c = {
. dump = ctnetlink_dump_table ,
. done = ctnetlink_done ,
+ . module = THIS_MODULE ,
};
#ifdef CONFIG_NF_CONNTRACK_MARK
if ( cda [ CTA_MARK ] && cda [ CTA_MARK_MASK ]) { @@ -1723,6 +1724,7 @@ ctnetlink_stat_ct_cpu(struct sock *ctnl, struct sk_buff *skb,
if ( nlh -> nlmsg_flags & NLM_F_DUMP ) {
struct netlink_dump_control c = {
. dump = ctnetlink_ct_stat_cpu_dump ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( ctnl , skb , nlh , & c );
} @@ -2242,6 +2244,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
struct netlink_dump_control c = {
. dump = ctnetlink_exp_dump_table ,
. done = ctnetlink_exp_done ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( ctnl , skb , nlh , & c );
} @@ -2680,6 +2683,7 @@ ctnetlink_stat_exp_cpu(struct sock *ctnl, struct sk_buff *skb,
if ( nlh -> nlmsg_flags & NLM_F_DUMP ) {
struct netlink_dump_control c = {
. dump = ctnetlink_exp_stat_cpu_dump ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( ctnl , skb , nlh , & c );
} --
1.7.7.6
set netlink_dump_control.module to avoid panic.
Signed-off-by: Gao feng <redacted>
---
net/netfilter/nfnetlink_acct.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index 589d686..8acf8b8 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c @@ -175,6 +175,7 @@ nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
if ( nlh -> nlmsg_flags & NLM_F_DUMP ) {
struct netlink_dump_control c = {
. dump = nfnl_acct_dump ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( nfnl , skb , nlh , & c );
} --
1.7.7.6
set netlink_dump_control.module to avoid panic.
Signed-off-by: Gao feng <redacted>
---
net/xfrm/xfrm_user.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 421f984..3d909f7 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c @@ -2308,17 +2308,20 @@ static struct xfrm_link {
int ( * doit )( struct sk_buff * , struct nlmsghdr * , struct nlattr ** );
int ( * dump )( struct sk_buff * , struct netlink_callback * );
int ( * done )( struct netlink_callback * );
+ struct module * module ;
} xfrm_dispatch [ XFRM_NR_MSGTYPES ] = {
[ XFRM_MSG_NEWSA - XFRM_MSG_BASE ] = { . doit = xfrm_add_sa },
[ XFRM_MSG_DELSA - XFRM_MSG_BASE ] = { . doit = xfrm_del_sa },
[ XFRM_MSG_GETSA - XFRM_MSG_BASE ] = { . doit = xfrm_get_sa ,
. dump = xfrm_dump_sa ,
- . done = xfrm_dump_sa_done },
+ . done = xfrm_dump_sa_done ,
+ . module = THIS_MODULE },
[ XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE ] = { . doit = xfrm_add_policy },
[ XFRM_MSG_DELPOLICY - XFRM_MSG_BASE ] = { . doit = xfrm_get_policy },
[ XFRM_MSG_GETPOLICY - XFRM_MSG_BASE ] = { . doit = xfrm_get_policy ,
. dump = xfrm_dump_policy ,
- . done = xfrm_dump_policy_done },
+ . done = xfrm_dump_policy_done ,
+ . module = THIS_MODULE },
[ XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE ] = { . doit = xfrm_alloc_userspi },
[ XFRM_MSG_ACQUIRE - XFRM_MSG_BASE ] = { . doit = xfrm_add_acquire },
[ XFRM_MSG_EXPIRE - XFRM_MSG_BASE ] = { . doit = xfrm_add_sa_expire }, @@ -2362,6 +2365,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
struct netlink_dump_control c = {
. dump = link -> dump ,
. done = link -> done ,
+ . module = link -> module ,
};
return netlink_dump_start ( net -> xfrm . nlsk , skb , nlh , & c );
} --
1.7.7.6
set netlink_dump_control.module to avoid panic.
Signed-off-by: Gao feng <redacted>
Cc: Jozsef Kadlecsik <redacted>
---
net/netfilter/ipset/ip_set_core.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 778465f..6f2b55c 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c @@ -1185,6 +1185,7 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
struct netlink_dump_control c = {
. dump = ip_set_dump_start ,
. done = ip_set_dump_done ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( ctnl , skb , nlh , & c );
} --
1.7.7.6
set netlink_dump_control.module to avoid panic.
Signed-off-by: Gao feng <redacted>
---
net/ipv4/inet_diag.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 535584c..5ffd7bc 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c @@ -981,6 +981,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct netlink_dump_control c = {
. dump = inet_diag_dump_compat ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( net -> diag_nlsk , skb , nlh , & c );
} @@ -1010,6 +1011,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
{
struct netlink_dump_control c = {
. dump = inet_diag_dump ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( net -> diag_nlsk , skb , h , & c );
} --
1.7.7.6
set netlink_dump_control.done to avoid panic.
Signed-off-by: Gao feng <redacted>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/crypto_user.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index 6bba414..f08297b 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c @@ -430,13 +430,15 @@ static struct crypto_link {
int ( * doit )( struct sk_buff * , struct nlmsghdr * , struct nlattr ** );
int ( * dump )( struct sk_buff * , struct netlink_callback * );
int ( * done )( struct netlink_callback * );
+ struct module * module ;
} crypto_dispatch [ CRYPTO_NR_MSGTYPES ] = {
[ CRYPTO_MSG_NEWALG - CRYPTO_MSG_BASE ] = { . doit = crypto_add_alg },
[ CRYPTO_MSG_DELALG - CRYPTO_MSG_BASE ] = { . doit = crypto_del_alg },
[ CRYPTO_MSG_UPDATEALG - CRYPTO_MSG_BASE ] = { . doit = crypto_update_alg },
[ CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE ] = { . doit = crypto_report ,
. dump = crypto_dump_report ,
- . done = crypto_dump_report_done },
+ . done = crypto_dump_report_done ,
+ . module = THIS_MODULE },
};
static int crypto_user_rcv_msg ( struct sk_buff * skb , struct nlmsghdr * nlh ) @@ -471,6 +473,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
. dump = link -> dump ,
. done = link -> done ,
. min_dump_alloc = dump_alloc ,
+ . module = link -> module ,
};
return netlink_dump_start ( crypto_nlsk , skb , nlh , & c );
} --
1.7.7.6
On Thu, 2012-10-04 at 12:41 +0800, Gao feng wrote: quoted hunk set netlink_dump_control.module to avoid panic.
Signed-off-by: Gao feng <redacted>
---
net/ipv4/inet_diag.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 535584c..5ffd7bc 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c @@ -981,6 +981,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct netlink_dump_control c = {
. dump = inet_diag_dump_compat ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( net -> diag_nlsk , skb , nlh , & c );
} @@ -1010,6 +1011,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
{
struct netlink_dump_control c = {
. dump = inet_diag_dump ,
+ . module = THIS_MODULE ,
};
return netlink_dump_start ( net -> diag_nlsk , skb , h , & c );
}
I believe Pablo suggestion was to make netlink_dump_start()
automatically pass THIS_MODULE so that we dont need to change all call
sites ?
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)
{
control->module = THIS_MODULE;
return __netlink_dump_start(ssk, skb, nlh, control);
}
or :
extern int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct netlink_dump_control *control,
struct module *module);
static inline int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct netlink_dump_control *control)
{
return __netlink_dump_start(ssk, skb, nlh, control, THIS_MODULE);
}
于 2012年10月04日 13:08, Eric Dumazet 写道: I believe Pablo suggestion was to make netlink_dump_start()
automatically pass THIS_MODULE so that we dont need to change all call
sites ?
Yes, since you and Pablo both think this should be better,
I will resend this patchset.
Thanks!
On Thu, 2012-10-04 at 12:41 +0800, Gao feng wrote: I get a panic when I use ss -a and rmmod inet_diag at the
same time.
it's because netlink_dump use inet_diag_dump witch function
belongs to module inet_diag.
I search the codes and find many modules have the same problem.
We need add reference of the module witch the cb->dump belongs
to.
Thanks for all help from Stephen,Jan,Eric,Steffen and Pablo.
Change From v2:
delete netlink_dump_done,and call module_put in netlink_dump
and netlink_sock_destruct. [...] quoted hunk @@ -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 witch cb->dump belong to */[...]
'which' not 'witch' :-)
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
于 2012年10月04日 23:41, Ben Hutchings 写道: 'which' not 'witch' :-)
Ben.
thanks Ben,will fix it :)