]> granicus.if.org Git - libnl/commitdiff
link: Protect registration of af and link ops with rwlock
authorThomas Graf <tgraf@suug.ch>
Thu, 15 Nov 2012 21:33:23 +0000 (22:33 +0100)
committerThomas Graf <tgraf@suug.ch>
Thu, 15 Nov 2012 21:33:23 +0000 (22:33 +0100)
Signed-off-by: Thomas Graf <tgraf@suug.ch>
lib/route/link/api.c

index f7907a78d2c91f8907bcda72e9007a8e87b44fe2..a12eb0931aade455cc6469655577ecd4f26692fc 100644 (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;
 }
 
 /** @} */