|
@@ -46,45 +46,43 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
|
|
|
|
|
|
static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
|
|
|
static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
|
|
|
+static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family);
|
|
|
+static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo);
|
|
|
|
|
|
int xfrm_register_type(struct xfrm_type *type, unsigned short family)
|
|
|
{
|
|
|
- struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
|
|
- struct xfrm_type_map *typemap;
|
|
|
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
|
|
|
+ struct xfrm_type **typemap;
|
|
|
int err = 0;
|
|
|
|
|
|
if (unlikely(afinfo == NULL))
|
|
|
return -EAFNOSUPPORT;
|
|
|
typemap = afinfo->type_map;
|
|
|
|
|
|
- write_lock_bh(&typemap->lock);
|
|
|
- if (likely(typemap->map[type->proto] == NULL))
|
|
|
- typemap->map[type->proto] = type;
|
|
|
+ if (likely(typemap[type->proto] == NULL))
|
|
|
+ typemap[type->proto] = type;
|
|
|
else
|
|
|
err = -EEXIST;
|
|
|
- write_unlock_bh(&typemap->lock);
|
|
|
- xfrm_policy_put_afinfo(afinfo);
|
|
|
+ xfrm_policy_unlock_afinfo(afinfo);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_register_type);
|
|
|
|
|
|
int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
|
|
|
{
|
|
|
- struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
|
|
- struct xfrm_type_map *typemap;
|
|
|
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
|
|
|
+ struct xfrm_type **typemap;
|
|
|
int err = 0;
|
|
|
|
|
|
if (unlikely(afinfo == NULL))
|
|
|
return -EAFNOSUPPORT;
|
|
|
typemap = afinfo->type_map;
|
|
|
|
|
|
- write_lock_bh(&typemap->lock);
|
|
|
- if (unlikely(typemap->map[type->proto] != type))
|
|
|
+ if (unlikely(typemap[type->proto] != type))
|
|
|
err = -ENOENT;
|
|
|
else
|
|
|
- typemap->map[type->proto] = NULL;
|
|
|
- write_unlock_bh(&typemap->lock);
|
|
|
- xfrm_policy_put_afinfo(afinfo);
|
|
|
+ typemap[type->proto] = NULL;
|
|
|
+ xfrm_policy_unlock_afinfo(afinfo);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_unregister_type);
|
|
@@ -92,7 +90,7 @@ EXPORT_SYMBOL(xfrm_unregister_type);
|
|
|
struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
|
|
|
{
|
|
|
struct xfrm_policy_afinfo *afinfo;
|
|
|
- struct xfrm_type_map *typemap;
|
|
|
+ struct xfrm_type **typemap;
|
|
|
struct xfrm_type *type;
|
|
|
int modload_attempted = 0;
|
|
|
|
|
@@ -102,11 +100,9 @@ retry:
|
|
|
return NULL;
|
|
|
typemap = afinfo->type_map;
|
|
|
|
|
|
- read_lock(&typemap->lock);
|
|
|
- type = typemap->map[proto];
|
|
|
+ type = typemap[proto];
|
|
|
if (unlikely(type && !try_module_get(type->owner)))
|
|
|
type = NULL;
|
|
|
- read_unlock(&typemap->lock);
|
|
|
if (!type && !modload_attempted) {
|
|
|
xfrm_policy_put_afinfo(afinfo);
|
|
|
request_module("xfrm-type-%d-%d",
|
|
@@ -1306,17 +1302,31 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
|
|
|
return NULL;
|
|
|
read_lock(&xfrm_policy_afinfo_lock);
|
|
|
afinfo = xfrm_policy_afinfo[family];
|
|
|
- if (likely(afinfo != NULL))
|
|
|
- read_lock(&afinfo->lock);
|
|
|
- read_unlock(&xfrm_policy_afinfo_lock);
|
|
|
+ if (unlikely(!afinfo))
|
|
|
+ read_unlock(&xfrm_policy_afinfo_lock);
|
|
|
return afinfo;
|
|
|
}
|
|
|
|
|
|
static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
|
|
|
{
|
|
|
- if (unlikely(afinfo == NULL))
|
|
|
- return;
|
|
|
- read_unlock(&afinfo->lock);
|
|
|
+ read_unlock(&xfrm_policy_afinfo_lock);
|
|
|
+}
|
|
|
+
|
|
|
+static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family)
|
|
|
+{
|
|
|
+ struct xfrm_policy_afinfo *afinfo;
|
|
|
+ if (unlikely(family >= NPROTO))
|
|
|
+ return NULL;
|
|
|
+ write_lock_bh(&xfrm_policy_afinfo_lock);
|
|
|
+ afinfo = xfrm_policy_afinfo[family];
|
|
|
+ if (unlikely(!afinfo))
|
|
|
+ write_unlock_bh(&xfrm_policy_afinfo_lock);
|
|
|
+ return afinfo;
|
|
|
+}
|
|
|
+
|
|
|
+static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo)
|
|
|
+{
|
|
|
+ write_unlock_bh(&xfrm_policy_afinfo_lock);
|
|
|
}
|
|
|
|
|
|
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
|