cache_mngt.c 9.8 KB

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