Home | History | Annotate | Download | only in lib
      1 /*
      2  * lib/cache_mngt.c	Cache Management
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2012 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup core
     14  * @defgroup cache_mngt Caching System
     15  *
     16  * Related sections in the development guide:
     17  * - @core_doc{core_cache, Caching System}
     18  *
     19  * @{
     20  *
     21  * Header
     22  * ------
     23  * ~~~~{.c}
     24  * #include <netlink/cache.h>
     25  * ~~~~
     26  */
     27 
     28 #include <netlink-private/netlink.h>
     29 #include <netlink/netlink.h>
     30 #include <netlink/cache.h>
     31 #include <netlink/utils.h>
     32 
     33 static struct nl_cache_ops *cache_ops;
     34 static NL_RW_LOCK(cache_ops_lock);
     35 
     36 /**
     37  * @name Cache Operations Sets
     38  * @{
     39  */
     40 
     41 struct nl_cache_ops *__nl_cache_ops_lookup(const char *name)
     42 {
     43 	struct nl_cache_ops *ops;
     44 
     45 	for (ops = cache_ops; ops; ops = ops->co_next)
     46 		if (!strcmp(ops->co_name, name))
     47 			return ops;
     48 
     49 	return NULL;
     50 }
     51 
     52 /**
     53  * Increment reference counter
     54  * @arg ops		Cache operations
     55  */
     56 void nl_cache_ops_get(struct nl_cache_ops *ops)
     57 {
     58 	ops->co_refcnt++;
     59 }
     60 
     61 /**
     62  * Decrement reference counter
     63  * @arg ops		Cache operations
     64  */
     65 void nl_cache_ops_put(struct nl_cache_ops *ops)
     66 {
     67 	ops->co_refcnt--;
     68 }
     69 
     70 /**
     71  * Lookup cache operations by name
     72  * @arg name		name of the cache type
     73  *
     74  * @attention This function is not safe, it does not increment the reference
     75  *            counter. Please use nl_cache_ops_lookup_safe().
     76  *
     77  * @return The cache operations or NULL if not found.
     78  */
     79 struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
     80 {
     81 	struct nl_cache_ops *ops;
     82 
     83 	nl_read_lock(&cache_ops_lock);
     84 	ops = __nl_cache_ops_lookup(name);
     85 	nl_read_unlock(&cache_ops_lock);
     86 
     87 	return ops;
     88 }
     89 
     90 /**
     91  * Lookup cache operations by name
     92  * @arg name		name of the cache type
     93  *
     94  * @note The reference counter of the returned cache operation is incremented
     95  *       and must be decremented after use with nl_cache_ops_put().
     96  *
     97  * @return The cache operations or NULL if not found.
     98  */
     99 struct nl_cache_ops *nl_cache_ops_lookup_safe(const char *name)
    100 {
    101 	struct nl_cache_ops *ops;
    102 
    103 	nl_write_lock(&cache_ops_lock);
    104 	if ((ops = __nl_cache_ops_lookup(name)))
    105 		nl_cache_ops_get(ops);
    106 	nl_write_unlock(&cache_ops_lock);
    107 
    108 	return ops;
    109 }
    110 
    111 static struct nl_cache_ops *__cache_ops_associate(int protocol, int msgtype)
    112 {
    113 	int i;
    114 	struct nl_cache_ops *ops;
    115 
    116 	for (ops = cache_ops; ops; ops = ops->co_next) {
    117 		if (ops->co_protocol != protocol)
    118 			continue;
    119 
    120 		for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
    121 			if (ops->co_msgtypes[i].mt_id == msgtype)
    122 				return ops;
    123 	}
    124 
    125 	return NULL;
    126 }
    127 
    128 /**
    129  * Associate protocol and message type to cache operations
    130  * @arg protocol		netlink protocol
    131  * @arg msgtype			netlink message type
    132  *
    133  * @attention This function is not safe, it does not increment the reference
    134  *            counter. Please use nl_cache_ops_associate_safe().
    135  *
    136  * @see nl_cache_ops_associate_safe()
    137  *
    138  * @return The cache operations or NULL if no match found.
    139  */
    140 struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
    141 {
    142 	struct nl_cache_ops *ops;
    143 
    144 	nl_read_lock(&cache_ops_lock);
    145 	ops = __cache_ops_associate(protocol, msgtype);
    146 	nl_read_unlock(&cache_ops_lock);
    147 
    148 	return ops;
    149 }
    150 
    151 /**
    152  * Associate protocol and message type to cache operations
    153  * @arg protocol		netlink protocol
    154  * @arg msgtype			netlink message type
    155  *
    156  * Searches the registered cache operations for a matching protocol
    157  * and message type.
    158  *
    159  * @note The reference counter of the returned cache operation is incremented
    160  *       and must be decremented after use with nl_cache_ops_put().
    161  *
    162  * @return The cache operations or NULL if no no match was found.
    163  */
    164 struct nl_cache_ops *nl_cache_ops_associate_safe(int protocol, int msgtype)
    165 {
    166 	struct nl_cache_ops *ops;
    167 
    168 	nl_write_lock(&cache_ops_lock);
    169 	if ((ops = __cache_ops_associate(protocol, msgtype)))
    170 		nl_cache_ops_get(ops);
    171 	nl_write_unlock(&cache_ops_lock);
    172 
    173 	return ops;
    174 }
    175 
    176 /**
    177  * Lookup message type cache association
    178  * @arg ops			cache operations
    179  * @arg msgtype			netlink message type
    180  *
    181  * Searches for a matching message type association ing the specified
    182  * cache operations.
    183  *
    184  * @attention The guranteed lifetime of the returned message type is bound
    185  *            to the lifetime of the underlying cache operations.
    186  *
    187  * @return A message type association or NULL.
    188  */
    189 struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
    190 {
    191 	int i;
    192 
    193 	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
    194 		if (ops->co_msgtypes[i].mt_id == msgtype)
    195 			return &ops->co_msgtypes[i];
    196 
    197 	return NULL;
    198 }
    199 
    200 /* Must hold cache_ops_lock */
    201 static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
    202 {
    203 	struct nl_cache_ops *ops;
    204 
    205 	for (ops = cache_ops; ops; ops = ops->co_next)
    206 		if (ops->co_obj_ops == obj_ops)
    207 			return ops;
    208 
    209 	return NULL;
    210 
    211 }
    212 
    213 /**
    214  * Call a function for each registered cache operation
    215  * @arg cb		Callback function to be called
    216  * @arg arg		User specific argument.
    217  */
    218 void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
    219 {
    220 	struct nl_cache_ops *ops;
    221 
    222 	nl_read_lock(&cache_ops_lock);
    223 	for (ops = cache_ops; ops; ops = ops->co_next)
    224 		cb(ops, arg);
    225 	nl_read_unlock(&cache_ops_lock);
    226 }
    227 
    228 /**
    229  * Set default flags for caches of this type
    230  * @arg ops		Cache ops
    231  * @arg flags		Flags to set
    232  *
    233  * The cache operation flags will be derived to all caches allocates
    234  * based on this set of cache operations.
    235  */
    236 void nl_cache_ops_set_flags(struct nl_cache_ops *ops, unsigned int flags)
    237 {
    238 	nl_write_lock(&cache_ops_lock);
    239 	ops->co_flags |= flags;
    240 	nl_write_unlock(&cache_ops_lock);
    241 }
    242 
    243 /**
    244  * Register a set of cache operations
    245  * @arg ops		cache operations
    246  *
    247  * Called by users of caches to announce the avaibility of
    248  * a certain cache type.
    249  *
    250  * @return 0 on success or a negative error code.
    251  */
    252 int nl_cache_mngt_register(struct nl_cache_ops *ops)
    253 {
    254 	if (!ops->co_name || !ops->co_obj_ops)
    255 		return -NLE_INVAL;
    256 
    257 	nl_write_lock(&cache_ops_lock);
    258 	if (__nl_cache_ops_lookup(ops->co_name)) {
    259 		nl_write_unlock(&cache_ops_lock);
    260 		return -NLE_EXIST;
    261 	}
    262 
    263 	ops->co_refcnt = 0;
    264 	ops->co_next = cache_ops;
    265 	cache_ops = ops;
    266 	nl_write_unlock(&cache_ops_lock);
    267 
    268 	NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
    269 
    270 	return 0;
    271 }
    272 
    273 /**
    274  * Unregister a set of cache operations
    275  * @arg ops		cache operations
    276  *
    277  * Called by users of caches to announce a set of
    278  * cache operations is no longer available. The
    279  * specified cache operations must have been registered
    280  * previously using nl_cache_mngt_register()
    281  *
    282  * @return 0 on success or a negative error code
    283  */
    284 int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
    285 {
    286 	struct nl_cache_ops *t, **tp;
    287 	int err = 0;
    288 
    289 	nl_write_lock(&cache_ops_lock);
    290 
    291 	if (ops->co_refcnt > 0) {
    292 		err = -NLE_BUSY;
    293 		goto errout;
    294 	}
    295 
    296 	for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
    297 		if (t == ops)
    298 			break;
    299 
    300 	if (!t) {
    301 		err = -NLE_NOCACHE;
    302 		goto errout;
    303 	}
    304 
    305 	NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
    306 
    307 	*tp = t->co_next;
    308 errout:
    309 	nl_write_unlock(&cache_ops_lock);
    310 
    311 	return err;
    312 }
    313 
    314 /** @} */
    315 
    316 /**
    317  * @name Global Cache Provisioning/Requiring
    318  * @{
    319  */
    320 
    321 /**
    322  * Provide a cache for global use
    323  * @arg cache		cache to provide
    324  *
    325  * Offers the specified cache to be used by other modules.
    326  * Only one cache per type may be shared at a time,
    327  * a previsouly provided caches will be overwritten.
    328  */
    329 void nl_cache_mngt_provide(struct nl_cache *cache)
    330 {
    331 	struct nl_cache_ops *ops;
    332 
    333 	nl_write_lock(&cache_ops_lock);
    334 
    335 	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
    336 	if (!ops)
    337 		BUG();
    338 	else {
    339 		nl_cache_get(cache);
    340 
    341 		/*
    342 		 * Hold a reference to the cache operations to ensure the
    343 		 * ops don't go away while we use it to store the cache pointer.
    344 		 */
    345 		if (!ops->co_major_cache)
    346 			nl_cache_ops_get(ops);
    347 
    348 		ops->co_major_cache = cache;
    349 	}
    350 
    351 	nl_write_unlock(&cache_ops_lock);
    352 }
    353 
    354 /**
    355  * Unprovide a cache for global use
    356  * @arg cache		cache to unprovide
    357  *
    358  * Cancels the offer to use a cache globally. The
    359  * cache will no longer be returned via lookups but
    360  * may still be in use.
    361  */
    362 void nl_cache_mngt_unprovide(struct nl_cache *cache)
    363 {
    364 	struct nl_cache_ops *ops;
    365 
    366 	nl_write_lock(&cache_ops_lock);
    367 
    368 	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
    369 	if (!ops)
    370 		BUG();
    371 	else if (ops->co_major_cache == cache) {
    372 		nl_cache_free(ops->co_major_cache);
    373 		nl_cache_ops_put(ops);
    374 		ops->co_major_cache = NULL;
    375 	}
    376 
    377 	nl_write_unlock(&cache_ops_lock);
    378 }
    379 
    380 struct nl_cache *__nl_cache_mngt_require(const char *name)
    381 {
    382 	struct nl_cache_ops *ops;
    383 	struct nl_cache *cache = NULL;
    384 
    385 	ops = nl_cache_ops_lookup_safe(name);
    386 	if (ops) {
    387 		cache = ops->co_major_cache;
    388 		nl_cache_ops_put(ops);
    389 	}
    390 
    391 	return cache;
    392 }
    393 
    394 /**
    395  * Return cache previously provided via nl_cache_mngt_provide()
    396  * @arg name		Name of cache to lookup
    397  *
    398  * @attention This function is not safe, it does not increment the reference
    399  *            counter. Please use nl_cache_mngt_require_safe().
    400  *
    401  * @see nl_cache_mngt_require_safe()
    402  *
    403  * @return Pointer to cache or NULL if none registered
    404  */
    405 struct nl_cache *nl_cache_mngt_require(const char *name)
    406 {
    407 	struct nl_cache *cache;
    408 
    409 	if (!(cache = __nl_cache_mngt_require(name)))
    410 		NL_DBG(1, "Application BUG: Your application must "
    411 		       "call nl_cache_mngt_provide() and\nprovide a valid "
    412 		       "%s cache to be used for internal lookups.\nSee the "
    413 		       " API documentation for more details.\n", name);
    414 
    415 	return cache;
    416 }
    417 
    418 /**
    419  * Return cache previously provided via nl_cache_mngt_provide()
    420  * @arg name		Name of cache to lookup
    421  *
    422  * @note The reference counter of the returned cache is incremented
    423  *       and must be decremented after use with nl_cache_put().
    424  *
    425  * @return Pointer to cache or NULL if none registered
    426  */
    427 struct nl_cache *nl_cache_mngt_require_safe(const char *name)
    428 {
    429 	struct nl_cache *cache;
    430 
    431 	if ((cache = nl_cache_mngt_require(name)))
    432 		nl_cache_get(cache);
    433 
    434 	return cache;
    435 }
    436 
    437 /** @} */
    438 
    439 /** @} */
    440