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