summaryrefslogtreecommitdiff
path: root/net/core/lwtunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/lwtunnel.c')
-rw-r--r--net/core/lwtunnel.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index 711cd3b4347a..6d3833269c2b 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -147,7 +147,8 @@ int lwtunnel_build_state(struct net *net, u16 encap_type,
}
EXPORT_SYMBOL_GPL(lwtunnel_build_state);
-int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack)
+int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack,
+ bool rtnl_is_held)
{
const struct lwtunnel_encap_ops *ops;
int ret = -EINVAL;
@@ -158,21 +159,19 @@ int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack)
return ret;
}
- rcu_read_lock();
- ops = rcu_dereference(lwtun_encaps[encap_type]);
- rcu_read_unlock();
+ ops = rcu_access_pointer(lwtun_encaps[encap_type]);
#ifdef CONFIG_MODULES
if (!ops) {
const char *encap_type_str = lwtunnel_encap_str(encap_type);
if (encap_type_str) {
- __rtnl_unlock();
+ if (rtnl_is_held)
+ __rtnl_unlock();
request_module("rtnl-lwt-%s", encap_type_str);
- rtnl_lock();
+ if (rtnl_is_held)
+ rtnl_lock();
- rcu_read_lock();
- ops = rcu_dereference(lwtun_encaps[encap_type]);
- rcu_read_unlock();
+ ops = rcu_access_pointer(lwtun_encaps[encap_type]);
}
}
#endif
@@ -185,7 +184,8 @@ int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack)
EXPORT_SYMBOL_GPL(lwtunnel_valid_encap_type);
int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining,
- struct netlink_ext_ack *extack)
+ struct netlink_ext_ack *extack,
+ bool rtnl_is_held)
{
struct rtnexthop *rtnh = (struct rtnexthop *)attr;
struct nlattr *nla_entype;
@@ -207,7 +207,8 @@ int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining,
encap_type = nla_get_u16(nla_entype);
if (lwtunnel_valid_encap_type(encap_type,
- extack) != 0)
+ extack,
+ rtnl_is_held) != 0)
return -EOPNOTSUPP;
}
}