dect
/
libnl
Archived
13
0
Fork 0

link: Protect registration of af and link ops with rwlock

Signed-off-by: Thomas Graf <tgraf@suug.ch>
This commit is contained in:
Thomas Graf 2012-11-15 22:33:23 +01:00
parent f5af5c5ecd
commit 74926f92dd
1 changed files with 57 additions and 17 deletions

View File

@ -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;
}
/** @} */