libnl  3.2.15
cache_mngt.c
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 /**
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-local.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  ops->co_flags |= flags;
239 }
240 
241 /**
242  * Register a set of cache operations
243  * @arg ops cache operations
244  *
245  * Called by users of caches to announce the avaibility of
246  * a certain cache type.
247  *
248  * @return 0 on success or a negative error code.
249  */
251 {
252  if (!ops->co_name || !ops->co_obj_ops)
253  return -NLE_INVAL;
254 
255  nl_write_lock(&cache_ops_lock);
256  if (__nl_cache_ops_lookup(ops->co_name)) {
257  nl_write_unlock(&cache_ops_lock);
258  return -NLE_EXIST;
259  }
260 
261  ops->co_refcnt = 0;
262  ops->co_next = cache_ops;
263  cache_ops = ops;
264  nl_write_unlock(&cache_ops_lock);
265 
266  NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
267 
268  return 0;
269 }
270 
271 /**
272  * Unregister a set of cache operations
273  * @arg ops cache operations
274  *
275  * Called by users of caches to announce a set of
276  * cache operations is no longer available. The
277  * specified cache operations must have been registered
278  * previously using nl_cache_mngt_register()
279  *
280  * @return 0 on success or a negative error code
281  */
283 {
284  struct nl_cache_ops *t, **tp;
285  int err = 0;
286 
287  nl_write_lock(&cache_ops_lock);
288 
289  if (ops->co_refcnt > 0) {
290  err = -NLE_BUSY;
291  goto errout;
292  }
293 
294  for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
295  if (t == ops)
296  break;
297 
298  if (!t) {
299  err = -NLE_NOCACHE;
300  goto errout;
301  }
302 
303  NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
304 
305  *tp = t->co_next;
306 errout:
307  nl_write_unlock(&cache_ops_lock);
308 
309  return err;
310 }
311 
312 /** @} */
313 
314 /**
315  * @name Global Cache Provisioning/Requiring
316  * @{
317  */
318 
319 /**
320  * Provide a cache for global use
321  * @arg cache cache to provide
322  *
323  * Offers the specified cache to be used by other modules.
324  * Only one cache per type may be shared at a time,
325  * a previsouly provided caches will be overwritten.
326  */
327 void nl_cache_mngt_provide(struct nl_cache *cache)
328 {
329  struct nl_cache_ops *ops;
330 
331  nl_write_lock(&cache_ops_lock);
332 
333  ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
334  if (!ops)
335  BUG();
336  else {
337  nl_cache_get(cache);
338 
339  /*
340  * Hold a reference to the cache operations to ensure the
341  * ops don't go away while we use it to store the cache pointer.
342  */
343  if (!ops->co_major_cache)
344  nl_cache_ops_get(ops);
345 
346  ops->co_major_cache = cache;
347  }
348 
349  nl_write_unlock(&cache_ops_lock);
350 }
351 
352 /**
353  * Unprovide a cache for global use
354  * @arg cache cache to unprovide
355  *
356  * Cancels the offer to use a cache globally. The
357  * cache will no longer be returned via lookups but
358  * may still be in use.
359  */
360 void nl_cache_mngt_unprovide(struct nl_cache *cache)
361 {
362  struct nl_cache_ops *ops;
363 
364  nl_write_lock(&cache_ops_lock);
365 
366  ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
367  if (!ops)
368  BUG();
369  else if (ops->co_major_cache == cache) {
370  nl_cache_free(ops->co_major_cache);
371  nl_cache_ops_put(ops);
372  ops->co_major_cache = NULL;
373  }
374 
375  nl_write_unlock(&cache_ops_lock);
376 }
377 
378 struct nl_cache *__nl_cache_mngt_require(const char *name)
379 {
380  struct nl_cache_ops *ops;
381  struct nl_cache *cache = NULL;
382 
383  ops = nl_cache_ops_lookup_safe(name);
384  if (ops) {
385  cache = ops->co_major_cache;
386  nl_cache_ops_put(ops);
387  }
388 
389  return cache;
390 }
391 
392 /**
393  * Return cache previously provided via nl_cache_mngt_provide()
394  * @arg name Name of cache to lookup
395  *
396  * @attention This function is not safe, it does not increment the reference
397  * counter. Please use nl_cache_mngt_require_safe().
398  *
399  * @see nl_cache_mngt_require_safe()
400  *
401  * @return Pointer to cache or NULL if none registered
402  */
403 struct nl_cache *nl_cache_mngt_require(const char *name)
404 {
405  struct nl_cache *cache;
406 
407  if (!(cache = __nl_cache_mngt_require(name)))
408  NL_DBG(1, "Application BUG: Your application must "
409  "call nl_cache_mngt_provide() and\nprovide a valid "
410  "%s cache to be used for internal lookups.\nSee the "
411  " API documentation for more details.\n", name);
412 
413  return cache;
414 }
415 
416 /**
417  * Return cache previously provided via nl_cache_mngt_provide()
418  * @arg name Name of cache to lookup
419  *
420  * @note The reference counter of the returned cache is incremented
421  * and must be decremented after use with nl_cache_put().
422  *
423  * @return Pointer to cache or NULL if none registered
424  */
425 struct nl_cache *nl_cache_mngt_require_safe(const char *name)
426 {
427  struct nl_cache *cache;
428 
429  if ((cache = nl_cache_mngt_require(name)))
430  nl_cache_get(cache);
431 
432  return cache;
433 }
434 
435 /** @} */
436 
437 /** @} */