Commit ec221a17 authored by David S. Miller's avatar David S. Miller

Merge branch 'lwt-module-unload'

Robert Shearman says:

====================
net: Fix oops on state free after lwt module unload

An oops is seen in lwtstate_free after an lwt ops module has been
unloaded. This patchset fixes this by preventing modules implementing
lwtunnel ops from being unloaded whilst there's state alive using
those ops. The first patch adds fills in a new owner field in all lwt
ops and the second patch makes use of this to reference count the
modules as state is built and destroyed using them.

Changes in v3:
 - don't put module reference if try_module_get fails on building state

Changes in v2:
 - specify module owner for all modules as suggested by DaveM
 - reference count all modules building lwt state, not just those ops
   implementing destroy_state, as also suggested by DaveM.
 - rebased on top of David Ahern's lwtunnel changes
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 04d7f1fb 85c81401
...@@ -44,6 +44,8 @@ struct lwtunnel_encap_ops { ...@@ -44,6 +44,8 @@ struct lwtunnel_encap_ops {
int (*get_encap_size)(struct lwtunnel_state *lwtstate); int (*get_encap_size)(struct lwtunnel_state *lwtstate);
int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b); int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b);
int (*xmit)(struct sk_buff *skb); int (*xmit)(struct sk_buff *skb);
struct module *owner;
}; };
#ifdef CONFIG_LWTUNNEL #ifdef CONFIG_LWTUNNEL
......
...@@ -386,6 +386,7 @@ static const struct lwtunnel_encap_ops bpf_encap_ops = { ...@@ -386,6 +386,7 @@ static const struct lwtunnel_encap_ops bpf_encap_ops = {
.fill_encap = bpf_fill_encap_info, .fill_encap = bpf_fill_encap_info,
.get_encap_size = bpf_encap_nlsize, .get_encap_size = bpf_encap_nlsize,
.cmp_encap = bpf_encap_cmp, .cmp_encap = bpf_encap_cmp,
.owner = THIS_MODULE,
}; };
static int __init bpf_lwt_init(void) static int __init bpf_lwt_init(void)
......
...@@ -115,8 +115,11 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type, ...@@ -115,8 +115,11 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
rcu_read_lock(); rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[encap_type]); ops = rcu_dereference(lwtun_encaps[encap_type]);
if (likely(ops && ops->build_state)) if (likely(ops && ops->build_state && try_module_get(ops->owner))) {
ret = ops->build_state(dev, encap, family, cfg, lws); ret = ops->build_state(dev, encap, family, cfg, lws);
if (ret)
module_put(ops->owner);
}
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;
...@@ -194,6 +197,7 @@ void lwtstate_free(struct lwtunnel_state *lws) ...@@ -194,6 +197,7 @@ void lwtstate_free(struct lwtunnel_state *lws)
} else { } else {
kfree(lws); kfree(lws);
} }
module_put(ops->owner);
} }
EXPORT_SYMBOL(lwtstate_free); EXPORT_SYMBOL(lwtstate_free);
......
...@@ -313,6 +313,7 @@ static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { ...@@ -313,6 +313,7 @@ static const struct lwtunnel_encap_ops ip_tun_lwt_ops = {
.fill_encap = ip_tun_fill_encap_info, .fill_encap = ip_tun_fill_encap_info,
.get_encap_size = ip_tun_encap_nlsize, .get_encap_size = ip_tun_encap_nlsize,
.cmp_encap = ip_tun_cmp_encap, .cmp_encap = ip_tun_cmp_encap,
.owner = THIS_MODULE,
}; };
static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = { static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = {
...@@ -403,6 +404,7 @@ static const struct lwtunnel_encap_ops ip6_tun_lwt_ops = { ...@@ -403,6 +404,7 @@ static const struct lwtunnel_encap_ops ip6_tun_lwt_ops = {
.fill_encap = ip6_tun_fill_encap_info, .fill_encap = ip6_tun_fill_encap_info,
.get_encap_size = ip6_tun_encap_nlsize, .get_encap_size = ip6_tun_encap_nlsize,
.cmp_encap = ip_tun_cmp_encap, .cmp_encap = ip_tun_cmp_encap,
.owner = THIS_MODULE,
}; };
void __init ip_tunnel_core_init(void) void __init ip_tunnel_core_init(void)
......
...@@ -238,6 +238,7 @@ static const struct lwtunnel_encap_ops ila_encap_ops = { ...@@ -238,6 +238,7 @@ static const struct lwtunnel_encap_ops ila_encap_ops = {
.fill_encap = ila_fill_encap_info, .fill_encap = ila_fill_encap_info,
.get_encap_size = ila_encap_nlsize, .get_encap_size = ila_encap_nlsize,
.cmp_encap = ila_encap_cmp, .cmp_encap = ila_encap_cmp,
.owner = THIS_MODULE,
}; };
int ila_lwt_init(void) int ila_lwt_init(void)
......
...@@ -422,6 +422,7 @@ static const struct lwtunnel_encap_ops seg6_iptun_ops = { ...@@ -422,6 +422,7 @@ static const struct lwtunnel_encap_ops seg6_iptun_ops = {
.fill_encap = seg6_fill_encap_info, .fill_encap = seg6_fill_encap_info,
.get_encap_size = seg6_encap_nlsize, .get_encap_size = seg6_encap_nlsize,
.cmp_encap = seg6_encap_cmp, .cmp_encap = seg6_encap_cmp,
.owner = THIS_MODULE,
}; };
int __init seg6_iptunnel_init(void) int __init seg6_iptunnel_init(void)
......
...@@ -215,6 +215,7 @@ static const struct lwtunnel_encap_ops mpls_iptun_ops = { ...@@ -215,6 +215,7 @@ static const struct lwtunnel_encap_ops mpls_iptun_ops = {
.fill_encap = mpls_fill_encap_info, .fill_encap = mpls_fill_encap_info,
.get_encap_size = mpls_encap_nlsize, .get_encap_size = mpls_encap_nlsize,
.cmp_encap = mpls_encap_cmp, .cmp_encap = mpls_encap_cmp,
.owner = THIS_MODULE,
}; };
static int __init mpls_iptunnel_init(void) static int __init mpls_iptunnel_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment