From 67aeb7474f3242bf9dc2e43b860643aa1da41a6e Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 11 Nov 2010 16:18:53 +0100 Subject: [PATCH] link/api: Convert link info ops to use nl_list_head rtnl_link_info_ops_lookup() now returns a pointer with refcnt increment, you must return it using rtnl_link_info_ops_put() --- include/netlink/route/link/api.h | 4 +- lib/route/link.c | 3 +- lib/route/link/api.c | 87 +++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/include/netlink/route/link/api.h b/include/netlink/route/link/api.h index ae5af59..42c00d9 100644 --- a/include/netlink/route/link/api.h +++ b/include/netlink/route/link/api.h @@ -60,11 +60,11 @@ struct rtnl_link_info_ops * in either io_alloc() or io_parse(). */ void (*io_free)(struct rtnl_link *); - struct rtnl_link_info_ops * io_next; + struct nl_list_head io_list; }; extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *); - +extern void rtnl_link_info_ops_put(struct rtnl_link_info_ops *); extern int rtnl_link_register_info(struct rtnl_link_info_ops *); extern int rtnl_link_unregister_info(struct rtnl_link_info_ops *); diff --git a/lib/route/link.c b/lib/route/link.c index 2082d6e..7aed708 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -266,8 +266,8 @@ static void release_link_info(struct rtnl_link *link) struct rtnl_link_info_ops *io = link->l_info_ops; if (io != NULL) { - io->io_refcnt--; io->io_free(link); + rtnl_link_info_ops_put(io); link->l_info_ops = NULL; } } @@ -562,7 +562,6 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, kind = nla_get_string(li[IFLA_INFO_KIND]); ops = rtnl_link_info_ops_lookup(kind); if (ops != NULL) { - ops->io_refcnt++; link->l_info_ops = ops; err = ops->io_parse(link, li[IFLA_INFO_DATA], li[IFLA_INFO_XSTATS]); diff --git a/lib/route/link/api.c b/lib/route/link/api.c index 9e14e4b..1830fe3 100644 --- a/lib/route/link/api.c +++ b/lib/route/link/api.c @@ -45,53 +45,106 @@ #include #include -static struct rtnl_link_info_ops *info_ops; +static NL_LIST_HEAD(info_ops); -struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name) +static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name) { struct rtnl_link_info_ops *ops; - for (ops = info_ops; ops; ops = ops->io_next) + nl_list_for_each_entry(ops, &info_ops, io_list) if (!strcmp(ops->io_name, name)) return ops; return NULL; } +/** + * Return operations of a specific link info type + * @arg name Name of link info type. + * + * @note The returned pointer must be given back using rtnl_link_info_ops_put() + * + * @return Pointer to operations or NULL if unavailable. + */ +struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name) +{ + struct rtnl_link_info_ops *ops; + + if ((ops = __rtnl_link_info_ops_lookup(name))) + ops->io_refcnt++; + + return ops; +} + +/** + * Give back reference to a set of operations. + * @arg ops Link info operations. + */ +void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops) +{ + if (ops) + ops->io_refcnt--; +} + +/** + * Register operations for a link info type + * @arg ops Link info operations + * + * This function must be called by modules implementing a specific link + * info type. It will make the operations implemented by the module + * available for everyone else. + * + * @return 0 on success or a negative error code. + * @return -NLE_INVAL Link info name not specified. + * @return -NLE_EXIST Operations for address family already registered. + */ int rtnl_link_register_info(struct rtnl_link_info_ops *ops) { if (ops->io_name == NULL) return -NLE_INVAL; - if (rtnl_link_info_ops_lookup(ops->io_name)) + if (__rtnl_link_info_ops_lookup(ops->io_name)) return -NLE_EXIST; NL_DBG(1, "Registered link info operations %s\n", ops->io_name); - ops->io_next = info_ops; - info_ops = ops; + nl_list_add_tail(&ops->io_list, &info_ops); return 0; } +/** + * Unregister operations for a link info type + * @arg ops Link info operations + * + * This function must be called if a module implementing a specific link + * info type is unloaded or becomes unavailable. It must provide a + * set of operations which have previously been registered using + * rtnl_link_register_info(). + * + * @return 0 on success or a negative error code + * @return _NLE_OPNOTSUPP Link info operations not registered. + * @return -NLE_BUSY Link info operations still in use. + */ int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops) { - struct rtnl_link_info_ops *t, **tp; + struct rtnl_link_info_ops *t; - for (tp = &info_ops; (t=*tp) != NULL; tp = &t->io_next) - if (t == ops) - break; + nl_list_for_each_entry(t, &info_ops, io_list) { + if (t == ops) { + if (t->io_refcnt > 0) + return -NLE_BUSY; - if (!t) - return -NLE_OPNOTSUPP; + nl_list_del(&t->io_list); - if (t->io_refcnt > 0) - return -NLE_BUSY; + NL_DBG(1, "Unregistered link info operations %s\n", + ops->io_name); - NL_DBG(1, "Unregistered link info perations %s\n", ops->io_name); + return 0; + } + } - *tp = t->io_next; - return 0; + return -NLE_OPNOTSUPP; } static struct rtnl_link_af_ops *af_ops[AF_MAX];