summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2012-11-15 22:33:23 +0100
committerThomas Graf <tgraf@suug.ch>2012-11-15 22:33:23 +0100
commit74926f92dd3a65e378def1a3e7309a027b8efbd3 (patch)
tree0ba76296b6ecb6653e5ba4cc304acffab82c57b7
parentf5af5c5ecd7245bef2f16fcb1e1270abbf435de0 (diff)
downloadlibnl-74926f92dd3a65e378def1a3e7309a027b8efbd3.tar.gz
link: Protect registration of af and link ops with rwlock
Signed-off-by: Thomas Graf <tgraf@suug.ch>
-rw-r--r--lib/route/link/api.c74
1 files changed, 57 insertions, 17 deletions
diff --git a/lib/route/link/api.c b/lib/route/link/api.c
index f7907a7..a12eb09 100644
--- a/lib/route/link/api.c
+++ b/lib/route/link/api.c
@@ -47,6 +47,9 @@
static NL_LIST_HEAD(info_ops);
+/* lock protecting info_ops and af_ops */
+static NL_RW_LOCK(info_lock);
+
static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name)
{
struct rtnl_link_info_ops *ops;
@@ -75,8 +78,10 @@ struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
{
struct rtnl_link_info_ops *ops;
+ nl_write_lock(&info_lock);
if ((ops = __rtnl_link_info_ops_lookup(name)))
ops->io_refcnt++;
+ nl_write_unlock(&info_lock);
return ops;
}
@@ -105,17 +110,24 @@ void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
*/
int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
{
+ int err = 0;
+
if (ops->io_name == NULL)
return -NLE_INVAL;
- if (__rtnl_link_info_ops_lookup(ops->io_name))
- return -NLE_EXIST;
+ nl_write_lock(&info_lock);
+ if (__rtnl_link_info_ops_lookup(ops->io_name)) {
+ err = -NLE_EXIST;
+ goto errout;
+ }
NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
nl_list_add_tail(&ops->io_list, &info_ops);
+errout:
+ nl_write_unlock(&info_lock);
- return 0;
+ return err;
}
/**
@@ -134,22 +146,30 @@ int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
{
struct rtnl_link_info_ops *t;
+ int err = -NLE_OPNOTSUPP;
+
+ nl_write_lock(&info_lock);
nl_list_for_each_entry(t, &info_ops, io_list) {
if (t == ops) {
- if (t->io_refcnt > 0)
- return -NLE_BUSY;
+ if (t->io_refcnt > 0) {
+ err = -NLE_BUSY;
+ goto errout;
+ }
nl_list_del(&t->io_list);
NL_DBG(1, "Unregistered link info operations %s\n",
ops->io_name);
-
- return 0;
+ err = 0;
+ goto errout;
}
}
- return -NLE_OPNOTSUPP;
+errout:
+ nl_write_unlock(&info_lock);
+
+ return err;
}
/** @} */
@@ -174,8 +194,10 @@ struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
if (family == AF_UNSPEC || family >= AF_MAX)
return NULL;
+ nl_write_lock(&info_lock);
if (af_ops[family])
af_ops[family]->ao_refcnt++;
+ nl_write_unlock(&info_lock);
return af_ops[family];
}
@@ -262,11 +284,16 @@ void *rtnl_link_af_data(const struct rtnl_link *link,
*/
int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
{
+ int err = 0;
+
if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
return -NLE_INVAL;
- if (af_ops[ops->ao_family])
- return -NLE_EXIST;
+ nl_write_lock(&info_lock);
+ if (af_ops[ops->ao_family]) {
+ err = -NLE_EXIST;
+ goto errout;
+ }
ops->ao_refcnt = 0;
af_ops[ops->ao_family] = ops;
@@ -274,7 +301,10 @@ int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
NL_DBG(1, "Registered link address family operations %u\n",
ops->ao_family);
- return 0;
+errout:
+ nl_write_unlock(&info_lock);
+
+ return err;
}
/**
@@ -293,21 +323,31 @@ int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
*/
int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
{
+ int err = -NLE_INVAL;
+
if (!ops)
- return -NLE_INVAL;
+ goto errout;
- if (!af_ops[ops->ao_family])
- return -NLE_OBJ_NOTFOUND;
+ nl_write_lock(&info_lock);
+ if (!af_ops[ops->ao_family]) {
+ err = -NLE_OBJ_NOTFOUND;
+ goto errout;
+ }
- if (ops->ao_refcnt > 0)
- return -NLE_BUSY;
+ if (ops->ao_refcnt > 0) {
+ err = -NLE_BUSY;
+ goto errout;
+ }
af_ops[ops->ao_family] = NULL;
NL_DBG(1, "Unregistered link address family operations %u\n",
ops->ao_family);
- return 0;
+errout:
+ nl_write_lock(&info_lock);
+
+ return err;
}
/** @} */