|
@@ -158,8 +158,8 @@ out_unlock:
|
|
|
mutex_unlock(&hash_resize_mutex);
|
|
|
}
|
|
|
|
|
|
-static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
|
|
|
-static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
|
|
|
+static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
|
|
|
+static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
|
|
|
|
|
|
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
|
|
|
|
|
@@ -168,58 +168,45 @@ int __xfrm_state_delete(struct xfrm_state *x);
|
|
|
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
|
|
|
void km_state_expired(struct xfrm_state *x, int hard, u32 portid);
|
|
|
|
|
|
-static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
|
|
|
-{
|
|
|
- struct xfrm_state_afinfo *afinfo;
|
|
|
- if (unlikely(family >= NPROTO))
|
|
|
- return NULL;
|
|
|
- write_lock_bh(&xfrm_state_afinfo_lock);
|
|
|
- afinfo = xfrm_state_afinfo[family];
|
|
|
- if (unlikely(!afinfo))
|
|
|
- write_unlock_bh(&xfrm_state_afinfo_lock);
|
|
|
- return afinfo;
|
|
|
-}
|
|
|
-
|
|
|
-static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
|
|
|
- __releases(xfrm_state_afinfo_lock)
|
|
|
-{
|
|
|
- write_unlock_bh(&xfrm_state_afinfo_lock);
|
|
|
-}
|
|
|
-
|
|
|
+static DEFINE_SPINLOCK(xfrm_type_lock);
|
|
|
int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
|
|
|
{
|
|
|
- struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
|
|
|
+ struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
|
|
|
const struct xfrm_type **typemap;
|
|
|
int err = 0;
|
|
|
|
|
|
if (unlikely(afinfo == NULL))
|
|
|
return -EAFNOSUPPORT;
|
|
|
typemap = afinfo->type_map;
|
|
|
+ spin_lock_bh(&xfrm_type_lock);
|
|
|
|
|
|
if (likely(typemap[type->proto] == NULL))
|
|
|
typemap[type->proto] = type;
|
|
|
else
|
|
|
err = -EEXIST;
|
|
|
- xfrm_state_unlock_afinfo(afinfo);
|
|
|
+ spin_unlock_bh(&xfrm_type_lock);
|
|
|
+ xfrm_state_put_afinfo(afinfo);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_register_type);
|
|
|
|
|
|
int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
|
|
|
{
|
|
|
- struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
|
|
|
+ struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
|
|
|
const struct xfrm_type **typemap;
|
|
|
int err = 0;
|
|
|
|
|
|
if (unlikely(afinfo == NULL))
|
|
|
return -EAFNOSUPPORT;
|
|
|
typemap = afinfo->type_map;
|
|
|
+ spin_lock_bh(&xfrm_type_lock);
|
|
|
|
|
|
if (unlikely(typemap[type->proto] != type))
|
|
|
err = -ENOENT;
|
|
|
else
|
|
|
typemap[type->proto] = NULL;
|
|
|
- xfrm_state_unlock_afinfo(afinfo);
|
|
|
+ spin_unlock_bh(&xfrm_type_lock);
|
|
|
+ xfrm_state_put_afinfo(afinfo);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_unregister_type);
|
|
@@ -256,6 +243,7 @@ static void xfrm_put_type(const struct xfrm_type *type)
|
|
|
module_put(type->owner);
|
|
|
}
|
|
|
|
|
|
+static DEFINE_SPINLOCK(xfrm_mode_lock);
|
|
|
int xfrm_register_mode(struct xfrm_mode *mode, int family)
|
|
|
{
|
|
|
struct xfrm_state_afinfo *afinfo;
|
|
@@ -265,12 +253,13 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family)
|
|
|
if (unlikely(mode->encap >= XFRM_MODE_MAX))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- afinfo = xfrm_state_lock_afinfo(family);
|
|
|
+ afinfo = xfrm_state_get_afinfo(family);
|
|
|
if (unlikely(afinfo == NULL))
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
|
|
err = -EEXIST;
|
|
|
modemap = afinfo->mode_map;
|
|
|
+ spin_lock_bh(&xfrm_mode_lock);
|
|
|
if (modemap[mode->encap])
|
|
|
goto out;
|
|
|
|
|
@@ -283,7 +272,8 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family)
|
|
|
err = 0;
|
|
|
|
|
|
out:
|
|
|
- xfrm_state_unlock_afinfo(afinfo);
|
|
|
+ spin_unlock_bh(&xfrm_mode_lock);
|
|
|
+ xfrm_state_put_afinfo(afinfo);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_register_mode);
|
|
@@ -297,19 +287,21 @@ int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
|
|
|
if (unlikely(mode->encap >= XFRM_MODE_MAX))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- afinfo = xfrm_state_lock_afinfo(family);
|
|
|
+ afinfo = xfrm_state_get_afinfo(family);
|
|
|
if (unlikely(afinfo == NULL))
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
|
|
err = -ENOENT;
|
|
|
modemap = afinfo->mode_map;
|
|
|
+ spin_lock_bh(&xfrm_mode_lock);
|
|
|
if (likely(modemap[mode->encap] == mode)) {
|
|
|
modemap[mode->encap] = NULL;
|
|
|
module_put(mode->afinfo->owner);
|
|
|
err = 0;
|
|
|
}
|
|
|
|
|
|
- xfrm_state_unlock_afinfo(afinfo);
|
|
|
+ spin_unlock_bh(&xfrm_mode_lock);
|
|
|
+ xfrm_state_put_afinfo(afinfo);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_unregister_mode);
|
|
@@ -1370,9 +1362,6 @@ int xfrm_state_check_expire(struct xfrm_state *x)
|
|
|
if (!x->curlft.use_time)
|
|
|
x->curlft.use_time = get_seconds();
|
|
|
|
|
|
- if (x->km.state != XFRM_STATE_VALID)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
if (x->curlft.bytes >= x->lft.hard_byte_limit ||
|
|
|
x->curlft.packets >= x->lft.hard_packet_limit) {
|
|
|
x->km.state = XFRM_STATE_EXPIRED;
|
|
@@ -1648,27 +1637,26 @@ static void xfrm_replay_timer_handler(unsigned long data)
|
|
|
}
|
|
|
|
|
|
static LIST_HEAD(xfrm_km_list);
|
|
|
-static DEFINE_RWLOCK(xfrm_km_lock);
|
|
|
|
|
|
void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
|
|
|
{
|
|
|
struct xfrm_mgr *km;
|
|
|
|
|
|
- read_lock(&xfrm_km_lock);
|
|
|
- list_for_each_entry(km, &xfrm_km_list, list)
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(km, &xfrm_km_list, list)
|
|
|
if (km->notify_policy)
|
|
|
km->notify_policy(xp, dir, c);
|
|
|
- read_unlock(&xfrm_km_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
void km_state_notify(struct xfrm_state *x, const struct km_event *c)
|
|
|
{
|
|
|
struct xfrm_mgr *km;
|
|
|
- read_lock(&xfrm_km_lock);
|
|
|
- list_for_each_entry(km, &xfrm_km_list, list)
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(km, &xfrm_km_list, list)
|
|
|
if (km->notify)
|
|
|
km->notify(x, c);
|
|
|
- read_unlock(&xfrm_km_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
EXPORT_SYMBOL(km_policy_notify);
|
|
@@ -1698,13 +1686,13 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
|
|
|
int err = -EINVAL, acqret;
|
|
|
struct xfrm_mgr *km;
|
|
|
|
|
|
- read_lock(&xfrm_km_lock);
|
|
|
- list_for_each_entry(km, &xfrm_km_list, list) {
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(km, &xfrm_km_list, list) {
|
|
|
acqret = km->acquire(x, t, pol);
|
|
|
if (!acqret)
|
|
|
err = acqret;
|
|
|
}
|
|
|
- read_unlock(&xfrm_km_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(km_query);
|
|
@@ -1714,14 +1702,14 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
|
|
|
int err = -EINVAL;
|
|
|
struct xfrm_mgr *km;
|
|
|
|
|
|
- read_lock(&xfrm_km_lock);
|
|
|
- list_for_each_entry(km, &xfrm_km_list, list) {
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(km, &xfrm_km_list, list) {
|
|
|
if (km->new_mapping)
|
|
|
err = km->new_mapping(x, ipaddr, sport);
|
|
|
if (!err)
|
|
|
break;
|
|
|
}
|
|
|
- read_unlock(&xfrm_km_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(km_new_mapping);
|
|
@@ -1750,15 +1738,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
|
|
int ret;
|
|
|
struct xfrm_mgr *km;
|
|
|
|
|
|
- read_lock(&xfrm_km_lock);
|
|
|
- list_for_each_entry(km, &xfrm_km_list, list) {
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(km, &xfrm_km_list, list) {
|
|
|
if (km->migrate) {
|
|
|
ret = km->migrate(sel, dir, type, m, num_migrate, k);
|
|
|
if (!ret)
|
|
|
err = ret;
|
|
|
}
|
|
|
}
|
|
|
- read_unlock(&xfrm_km_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(km_migrate);
|
|
@@ -1770,15 +1758,15 @@ int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address
|
|
|
int ret;
|
|
|
struct xfrm_mgr *km;
|
|
|
|
|
|
- read_lock(&xfrm_km_lock);
|
|
|
- list_for_each_entry(km, &xfrm_km_list, list) {
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(km, &xfrm_km_list, list) {
|
|
|
if (km->report) {
|
|
|
ret = km->report(net, proto, sel, addr);
|
|
|
if (!ret)
|
|
|
err = ret;
|
|
|
}
|
|
|
}
|
|
|
- read_unlock(&xfrm_km_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(km_report);
|
|
@@ -1802,14 +1790,14 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
|
|
|
goto out;
|
|
|
|
|
|
err = -EINVAL;
|
|
|
- read_lock(&xfrm_km_lock);
|
|
|
- list_for_each_entry(km, &xfrm_km_list, list) {
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(km, &xfrm_km_list, list) {
|
|
|
pol = km->compile_policy(sk, optname, data,
|
|
|
optlen, &err);
|
|
|
if (err >= 0)
|
|
|
break;
|
|
|
}
|
|
|
- read_unlock(&xfrm_km_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
|
|
|
if (err >= 0) {
|
|
|
xfrm_sk_policy_insert(sk, err, pol);
|
|
@@ -1823,20 +1811,23 @@ out:
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_user_policy);
|
|
|
|
|
|
+static DEFINE_SPINLOCK(xfrm_km_lock);
|
|
|
+
|
|
|
int xfrm_register_km(struct xfrm_mgr *km)
|
|
|
{
|
|
|
- write_lock_bh(&xfrm_km_lock);
|
|
|
- list_add_tail(&km->list, &xfrm_km_list);
|
|
|
- write_unlock_bh(&xfrm_km_lock);
|
|
|
+ spin_lock_bh(&xfrm_km_lock);
|
|
|
+ list_add_tail_rcu(&km->list, &xfrm_km_list);
|
|
|
+ spin_unlock_bh(&xfrm_km_lock);
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_register_km);
|
|
|
|
|
|
int xfrm_unregister_km(struct xfrm_mgr *km)
|
|
|
{
|
|
|
- write_lock_bh(&xfrm_km_lock);
|
|
|
- list_del(&km->list);
|
|
|
- write_unlock_bh(&xfrm_km_lock);
|
|
|
+ spin_lock_bh(&xfrm_km_lock);
|
|
|
+ list_del_rcu(&km->list);
|
|
|
+ spin_unlock_bh(&xfrm_km_lock);
|
|
|
+ synchronize_rcu();
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_unregister_km);
|
|
@@ -1848,12 +1839,12 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
|
|
|
return -EINVAL;
|
|
|
if (unlikely(afinfo->family >= NPROTO))
|
|
|
return -EAFNOSUPPORT;
|
|
|
- write_lock_bh(&xfrm_state_afinfo_lock);
|
|
|
+ spin_lock_bh(&xfrm_state_afinfo_lock);
|
|
|
if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
|
|
|
err = -ENOBUFS;
|
|
|
else
|
|
|
- xfrm_state_afinfo[afinfo->family] = afinfo;
|
|
|
- write_unlock_bh(&xfrm_state_afinfo_lock);
|
|
|
+ rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo);
|
|
|
+ spin_unlock_bh(&xfrm_state_afinfo_lock);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_state_register_afinfo);
|
|
@@ -1865,14 +1856,15 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
|
|
|
return -EINVAL;
|
|
|
if (unlikely(afinfo->family >= NPROTO))
|
|
|
return -EAFNOSUPPORT;
|
|
|
- write_lock_bh(&xfrm_state_afinfo_lock);
|
|
|
+ spin_lock_bh(&xfrm_state_afinfo_lock);
|
|
|
if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
|
|
|
if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
|
|
|
err = -EINVAL;
|
|
|
else
|
|
|
- xfrm_state_afinfo[afinfo->family] = NULL;
|
|
|
+ RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL);
|
|
|
}
|
|
|
- write_unlock_bh(&xfrm_state_afinfo_lock);
|
|
|
+ spin_unlock_bh(&xfrm_state_afinfo_lock);
|
|
|
+ synchronize_rcu();
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
|
|
@@ -1882,17 +1874,16 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
|
|
|
struct xfrm_state_afinfo *afinfo;
|
|
|
if (unlikely(family >= NPROTO))
|
|
|
return NULL;
|
|
|
- read_lock(&xfrm_state_afinfo_lock);
|
|
|
- afinfo = xfrm_state_afinfo[family];
|
|
|
+ rcu_read_lock();
|
|
|
+ afinfo = rcu_dereference(xfrm_state_afinfo[family]);
|
|
|
if (unlikely(!afinfo))
|
|
|
- read_unlock(&xfrm_state_afinfo_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
return afinfo;
|
|
|
}
|
|
|
|
|
|
static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
|
|
|
- __releases(xfrm_state_afinfo_lock)
|
|
|
{
|
|
|
- read_unlock(&xfrm_state_afinfo_lock);
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
|