cache_mngt.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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-2006 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @defgroup cache_mngt Caching
  13. * @{
  14. */
  15. #include <netlink-local.h>
  16. #include <netlink/netlink.h>
  17. #include <netlink/cache.h>
  18. #include <netlink/utils.h>
  19. static struct nl_cache_ops *cache_ops;
  20. static NL_RW_LOCK(cache_ops_lock);
  21. /**
  22. * @name Cache Operations Sets
  23. * @{
  24. */
  25. struct nl_cache_ops *__nl_cache_ops_lookup(const char *name)
  26. {
  27. struct nl_cache_ops *ops;
  28. for (ops = cache_ops; ops; ops = ops->co_next)
  29. if (!strcmp(ops->co_name, name))
  30. return ops;
  31. return NULL;
  32. }
  33. /**
  34. * Increment reference counter
  35. * @arg ops Cache operations
  36. */
  37. void nl_cache_ops_get(struct nl_cache_ops *ops)
  38. {
  39. ops->co_refcnt++;
  40. }
  41. /**
  42. * Decrement reference counter
  43. * @arg ops Cache operations
  44. */
  45. void nl_cache_ops_put(struct nl_cache_ops *ops)
  46. {
  47. ops->co_refcnt--;
  48. }
  49. /**
  50. * Lookup cache operations by name
  51. * @arg name name of the cache type
  52. *
  53. * @attention This function is not safe, it does not increment the reference
  54. * counter. Please use nl_cache_ops_lookup_safe().
  55. *
  56. * @return The cache operations or NULL if not found.
  57. */
  58. struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
  59. {
  60. struct nl_cache_ops *ops;
  61. nl_read_lock(&cache_ops_lock);
  62. ops = __nl_cache_ops_lookup(name);
  63. nl_read_unlock(&cache_ops_lock);
  64. return ops;
  65. }
  66. /**
  67. * Lookup cache operations by name
  68. * @arg name name of the cache type
  69. *
  70. * @note The reference counter of the returned cache operation is incremented
  71. * and must be decremented after use with nl_cache_ops_put().
  72. *
  73. * @return The cache operations or NULL if not found.
  74. */
  75. struct nl_cache_ops *nl_cache_ops_lookup_safe(const char *name)
  76. {
  77. struct nl_cache_ops *ops;
  78. nl_write_lock(&cache_ops_lock);
  79. if ((ops = __nl_cache_ops_lookup(name)))
  80. nl_cache_ops_get(ops);
  81. nl_write_unlock(&cache_ops_lock);
  82. return ops;
  83. }
  84. static struct nl_cache_ops *__cache_ops_associate(int protocol, int msgtype)
  85. {
  86. int i;
  87. struct nl_cache_ops *ops;
  88. for (ops = cache_ops; ops; ops = ops->co_next) {
  89. if (ops->co_protocol != protocol)
  90. continue;
  91. for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
  92. if (ops->co_msgtypes[i].mt_id == msgtype)
  93. return ops;
  94. }
  95. return NULL;
  96. }
  97. /**
  98. * Associate protocol and message type to cache operations
  99. * @arg protocol netlink protocol
  100. * @arg msgtype netlink message type
  101. *
  102. * @attention This function is not safe, it does not increment the reference
  103. * counter. Please use nl_cache_ops_associate_safe().
  104. *
  105. * @see nl_cache_ops_associate_safe()
  106. *
  107. * @return The cache operations or NULL if no match found.
  108. */
  109. struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
  110. {
  111. struct nl_cache_ops *ops;
  112. nl_read_lock(&cache_ops_lock);
  113. ops = __cache_ops_associate(protocol, msgtype);
  114. nl_read_unlock(&cache_ops_lock);
  115. return ops;
  116. }
  117. /**
  118. * Associate protocol and message type to cache operations
  119. * @arg protocol netlink protocol
  120. * @arg msgtype netlink message type
  121. *
  122. * Searches the registered cache operations for a matching protocol
  123. * and message type.
  124. *
  125. * @note The reference counter of the returned cache operation is incremented
  126. * and must be decremented after use with nl_cache_ops_put().
  127. *
  128. * @return The cache operations or NULL if no no match was found.
  129. */
  130. struct nl_cache_ops *nl_cache_ops_associate_safe(int protocol, int msgtype)
  131. {
  132. struct nl_cache_ops *ops;
  133. nl_write_lock(&cache_ops_lock);
  134. if ((ops = __cache_ops_associate(protocol, msgtype)))
  135. nl_cache_ops_get(ops);
  136. nl_write_unlock(&cache_ops_lock);
  137. return ops;
  138. }
  139. /**
  140. * Lookup message type cache association
  141. * @arg ops cache operations
  142. * @arg msgtype netlink message type
  143. *
  144. * Searches for a matching message type association ing the specified
  145. * cache operations.
  146. *
  147. * @attention The guranteed lifetime of the returned message type is bound
  148. * to the lifetime of the underlying cache operations.
  149. *
  150. * @return A message type association or NULL.
  151. */
  152. struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
  153. {
  154. int i;
  155. for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
  156. if (ops->co_msgtypes[i].mt_id == msgtype)
  157. return &ops->co_msgtypes[i];
  158. return NULL;
  159. }
  160. /* Must hold cache_ops_lock */
  161. static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
  162. {
  163. struct nl_cache_ops *ops;
  164. for (ops = cache_ops; ops; ops = ops->co_next)
  165. if (ops->co_obj_ops == obj_ops)
  166. return ops;
  167. return NULL;
  168. }
  169. /**
  170. * Call a function for each registered cache operation
  171. * @arg cb Callback function to be called
  172. * @arg arg User specific argument.
  173. */
  174. void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
  175. {
  176. struct nl_cache_ops *ops;
  177. nl_read_lock(&cache_ops_lock);
  178. for (ops = cache_ops; ops; ops = ops->co_next)
  179. cb(ops, arg);
  180. nl_read_unlock(&cache_ops_lock);
  181. }
  182. /**
  183. * Register a set of cache operations
  184. * @arg ops cache operations
  185. *
  186. * Called by users of caches to announce the avaibility of
  187. * a certain cache type.
  188. *
  189. * @return 0 on success or a negative error code.
  190. */
  191. int nl_cache_mngt_register(struct nl_cache_ops *ops)
  192. {
  193. if (!ops->co_name)
  194. return nl_error(EINVAL, "No cache name specified");
  195. if (!ops->co_obj_ops)
  196. return nl_error(EINVAL, "No obj cache ops specified");
  197. nl_write_lock(&cache_ops_lock);
  198. if (__nl_cache_ops_lookup(ops->co_name)) {
  199. nl_write_unlock(&cache_ops_lock);
  200. return nl_error(EEXIST, "Cache operations already exist");
  201. }
  202. ops->co_refcnt = 0;
  203. ops->co_next = cache_ops;
  204. cache_ops = ops;
  205. nl_write_unlock(&cache_ops_lock);
  206. NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
  207. return 0;
  208. }
  209. /**
  210. * Unregister a set of cache operations
  211. * @arg ops cache operations
  212. *
  213. * Called by users of caches to announce a set of
  214. * cache operations is no longer available. The
  215. * specified cache operations must have been registered
  216. * previously using nl_cache_mngt_register()
  217. *
  218. * @return 0 on success or a negative error code
  219. */
  220. int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
  221. {
  222. struct nl_cache_ops *t, **tp;
  223. nl_write_lock(&cache_ops_lock);
  224. if (ops->co_refcnt > 0) {
  225. nl_write_unlock(&cache_ops_lock);
  226. return nl_error(EBUSY, "Cache operations busy");
  227. }
  228. for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
  229. if (t == ops)
  230. break;
  231. if (!t) {
  232. nl_write_unlock(&cache_ops_lock);
  233. return nl_error(ENOENT, "No such cache operations");
  234. }
  235. NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
  236. *tp = t->co_next;
  237. nl_write_unlock(&cache_ops_lock);
  238. return 0;
  239. }
  240. /** @} */
  241. /**
  242. * @name Global Cache Provisioning/Requiring
  243. * @{
  244. */
  245. /**
  246. * Provide a cache for global use
  247. * @arg cache cache to provide
  248. *
  249. * Offers the specified cache to be used by other modules.
  250. * Only one cache per type may be shared at a time,
  251. * a previsouly provided caches will be overwritten.
  252. */
  253. void nl_cache_mngt_provide(struct nl_cache *cache)
  254. {
  255. struct nl_cache_ops *ops;
  256. nl_write_lock(&cache_ops_lock);
  257. ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
  258. if (!ops)
  259. BUG();
  260. else {
  261. nl_cache_get(cache);
  262. ops->co_major_cache = cache;
  263. }
  264. nl_write_unlock(&cache_ops_lock);
  265. }
  266. /**
  267. * Unprovide a cache for global use
  268. * @arg cache cache to unprovide
  269. *
  270. * Cancels the offer to use a cache globally. The
  271. * cache will no longer be returned via lookups but
  272. * may still be in use.
  273. */
  274. void nl_cache_mngt_unprovide(struct nl_cache *cache)
  275. {
  276. struct nl_cache_ops *ops;
  277. nl_write_lock(&cache_ops_lock);
  278. ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
  279. if (!ops)
  280. BUG();
  281. else if (ops->co_major_cache == cache) {
  282. nl_cache_free(ops->co_major_cache);
  283. ops->co_major_cache = NULL;
  284. }
  285. nl_write_unlock(&cache_ops_lock);
  286. }
  287. /**
  288. * Demand the use of a global cache
  289. * @arg name name of the required object type
  290. *
  291. * Trys to find a cache of the specified type for global
  292. * use.
  293. *
  294. * @return A cache provided by another subsystem of the
  295. * specified type marked to be available.
  296. */
  297. struct nl_cache *nl_cache_mngt_require(const char *name)
  298. {
  299. struct nl_cache_ops *ops;
  300. ops = nl_cache_ops_lookup(name);
  301. if (!ops || !ops->co_major_cache) {
  302. fprintf(stderr, "Application BUG: Your application must "
  303. "call nl_cache_mngt_provide() and\nprovide a valid "
  304. "%s cache to be used for internal lookups.\nSee the "
  305. " API documentation for more details.\n", name);
  306. return NULL;
  307. }
  308. return ops->co_major_cache;
  309. }
  310. /** @} */
  311. /** @} */