1c6b4fcbaSJoe Thornber /* 2c6b4fcbaSJoe Thornber * Copyright (C) 2012 Red Hat. All rights reserved. 3c6b4fcbaSJoe Thornber * 4c6b4fcbaSJoe Thornber * This file is released under the GPL. 5c6b4fcbaSJoe Thornber */ 6c6b4fcbaSJoe Thornber 7c6b4fcbaSJoe Thornber #include "dm-cache-policy-internal.h" 8c6b4fcbaSJoe Thornber #include "dm.h" 9c6b4fcbaSJoe Thornber 10c6b4fcbaSJoe Thornber #include <linux/module.h> 11c6b4fcbaSJoe Thornber #include <linux/slab.h> 12c6b4fcbaSJoe Thornber 13c6b4fcbaSJoe Thornber /*----------------------------------------------------------------*/ 14c6b4fcbaSJoe Thornber 15c6b4fcbaSJoe Thornber #define DM_MSG_PREFIX "cache-policy" 16c6b4fcbaSJoe Thornber 17c6b4fcbaSJoe Thornber static DEFINE_SPINLOCK(register_lock); 18c6b4fcbaSJoe Thornber static LIST_HEAD(register_list); 19c6b4fcbaSJoe Thornber 20c6b4fcbaSJoe Thornber static struct dm_cache_policy_type *__find_policy(const char *name) 21c6b4fcbaSJoe Thornber { 22c6b4fcbaSJoe Thornber struct dm_cache_policy_type *t; 23c6b4fcbaSJoe Thornber 24c6b4fcbaSJoe Thornber list_for_each_entry(t, ®ister_list, list) 25c6b4fcbaSJoe Thornber if (!strcmp(t->name, name)) 26c6b4fcbaSJoe Thornber return t; 27c6b4fcbaSJoe Thornber 28c6b4fcbaSJoe Thornber return NULL; 29c6b4fcbaSJoe Thornber } 30c6b4fcbaSJoe Thornber 31c6b4fcbaSJoe Thornber static struct dm_cache_policy_type *__get_policy_once(const char *name) 32c6b4fcbaSJoe Thornber { 33c6b4fcbaSJoe Thornber struct dm_cache_policy_type *t = __find_policy(name); 34c6b4fcbaSJoe Thornber 35c6b4fcbaSJoe Thornber if (t && !try_module_get(t->owner)) { 36c6b4fcbaSJoe Thornber DMWARN("couldn't get module %s", name); 37c6b4fcbaSJoe Thornber t = ERR_PTR(-EINVAL); 38c6b4fcbaSJoe Thornber } 39c6b4fcbaSJoe Thornber 40c6b4fcbaSJoe Thornber return t; 41c6b4fcbaSJoe Thornber } 42c6b4fcbaSJoe Thornber 43c6b4fcbaSJoe Thornber static struct dm_cache_policy_type *get_policy_once(const char *name) 44c6b4fcbaSJoe Thornber { 45c6b4fcbaSJoe Thornber struct dm_cache_policy_type *t; 46c6b4fcbaSJoe Thornber 47c6b4fcbaSJoe Thornber spin_lock(®ister_lock); 48c6b4fcbaSJoe Thornber t = __get_policy_once(name); 49c6b4fcbaSJoe Thornber spin_unlock(®ister_lock); 50c6b4fcbaSJoe Thornber 51c6b4fcbaSJoe Thornber return t; 52c6b4fcbaSJoe Thornber } 53c6b4fcbaSJoe Thornber 54c6b4fcbaSJoe Thornber static struct dm_cache_policy_type *get_policy(const char *name) 55c6b4fcbaSJoe Thornber { 56c6b4fcbaSJoe Thornber struct dm_cache_policy_type *t; 57c6b4fcbaSJoe Thornber 58c6b4fcbaSJoe Thornber t = get_policy_once(name); 59c6b4fcbaSJoe Thornber if (IS_ERR(t)) 60c6b4fcbaSJoe Thornber return NULL; 61c6b4fcbaSJoe Thornber 62c6b4fcbaSJoe Thornber if (t) 63c6b4fcbaSJoe Thornber return t; 64c6b4fcbaSJoe Thornber 65c6b4fcbaSJoe Thornber request_module("dm-cache-%s", name); 66c6b4fcbaSJoe Thornber 67c6b4fcbaSJoe Thornber t = get_policy_once(name); 68c6b4fcbaSJoe Thornber if (IS_ERR(t)) 69c6b4fcbaSJoe Thornber return NULL; 70c6b4fcbaSJoe Thornber 71c6b4fcbaSJoe Thornber return t; 72c6b4fcbaSJoe Thornber } 73c6b4fcbaSJoe Thornber 74c6b4fcbaSJoe Thornber static void put_policy(struct dm_cache_policy_type *t) 75c6b4fcbaSJoe Thornber { 76c6b4fcbaSJoe Thornber module_put(t->owner); 77c6b4fcbaSJoe Thornber } 78c6b4fcbaSJoe Thornber 79c6b4fcbaSJoe Thornber int dm_cache_policy_register(struct dm_cache_policy_type *type) 80c6b4fcbaSJoe Thornber { 81c6b4fcbaSJoe Thornber int r; 82c6b4fcbaSJoe Thornber 83c6b4fcbaSJoe Thornber /* One size fits all for now */ 84c6b4fcbaSJoe Thornber if (type->hint_size != 0 && type->hint_size != 4) { 85c6b4fcbaSJoe Thornber DMWARN("hint size must be 0 or 4 but %llu supplied.", (unsigned long long) type->hint_size); 86c6b4fcbaSJoe Thornber return -EINVAL; 87c6b4fcbaSJoe Thornber } 88c6b4fcbaSJoe Thornber 89c6b4fcbaSJoe Thornber spin_lock(®ister_lock); 90c6b4fcbaSJoe Thornber if (__find_policy(type->name)) { 91c6b4fcbaSJoe Thornber DMWARN("attempt to register policy under duplicate name %s", type->name); 92c6b4fcbaSJoe Thornber r = -EINVAL; 93c6b4fcbaSJoe Thornber } else { 94c6b4fcbaSJoe Thornber list_add(&type->list, ®ister_list); 95c6b4fcbaSJoe Thornber r = 0; 96c6b4fcbaSJoe Thornber } 97c6b4fcbaSJoe Thornber spin_unlock(®ister_lock); 98c6b4fcbaSJoe Thornber 99c6b4fcbaSJoe Thornber return r; 100c6b4fcbaSJoe Thornber } 101c6b4fcbaSJoe Thornber EXPORT_SYMBOL_GPL(dm_cache_policy_register); 102c6b4fcbaSJoe Thornber 103c6b4fcbaSJoe Thornber void dm_cache_policy_unregister(struct dm_cache_policy_type *type) 104c6b4fcbaSJoe Thornber { 105c6b4fcbaSJoe Thornber spin_lock(®ister_lock); 106c6b4fcbaSJoe Thornber list_del_init(&type->list); 107c6b4fcbaSJoe Thornber spin_unlock(®ister_lock); 108c6b4fcbaSJoe Thornber } 109c6b4fcbaSJoe Thornber EXPORT_SYMBOL_GPL(dm_cache_policy_unregister); 110c6b4fcbaSJoe Thornber 111c6b4fcbaSJoe Thornber struct dm_cache_policy *dm_cache_policy_create(const char *name, 112c6b4fcbaSJoe Thornber dm_cblock_t cache_size, 113c6b4fcbaSJoe Thornber sector_t origin_size, 114c6b4fcbaSJoe Thornber sector_t cache_block_size) 115c6b4fcbaSJoe Thornber { 116c6b4fcbaSJoe Thornber struct dm_cache_policy *p = NULL; 117c6b4fcbaSJoe Thornber struct dm_cache_policy_type *type; 118c6b4fcbaSJoe Thornber 119c6b4fcbaSJoe Thornber type = get_policy(name); 120c6b4fcbaSJoe Thornber if (!type) { 121c6b4fcbaSJoe Thornber DMWARN("unknown policy type"); 122c6b4fcbaSJoe Thornber return NULL; 123c6b4fcbaSJoe Thornber } 124c6b4fcbaSJoe Thornber 125c6b4fcbaSJoe Thornber p = type->create(cache_size, origin_size, cache_block_size); 126c6b4fcbaSJoe Thornber if (!p) { 127c6b4fcbaSJoe Thornber put_policy(type); 128c6b4fcbaSJoe Thornber return NULL; 129c6b4fcbaSJoe Thornber } 130c6b4fcbaSJoe Thornber p->private = type; 131c6b4fcbaSJoe Thornber 132c6b4fcbaSJoe Thornber return p; 133c6b4fcbaSJoe Thornber } 134c6b4fcbaSJoe Thornber EXPORT_SYMBOL_GPL(dm_cache_policy_create); 135c6b4fcbaSJoe Thornber 136c6b4fcbaSJoe Thornber void dm_cache_policy_destroy(struct dm_cache_policy *p) 137c6b4fcbaSJoe Thornber { 138c6b4fcbaSJoe Thornber struct dm_cache_policy_type *t = p->private; 139c6b4fcbaSJoe Thornber 140c6b4fcbaSJoe Thornber p->destroy(p); 141c6b4fcbaSJoe Thornber put_policy(t); 142c6b4fcbaSJoe Thornber } 143c6b4fcbaSJoe Thornber EXPORT_SYMBOL_GPL(dm_cache_policy_destroy); 144c6b4fcbaSJoe Thornber 145c6b4fcbaSJoe Thornber const char *dm_cache_policy_get_name(struct dm_cache_policy *p) 146c6b4fcbaSJoe Thornber { 147c6b4fcbaSJoe Thornber struct dm_cache_policy_type *t = p->private; 148c6b4fcbaSJoe Thornber 149c6b4fcbaSJoe Thornber return t->name; 150c6b4fcbaSJoe Thornber } 151c6b4fcbaSJoe Thornber EXPORT_SYMBOL_GPL(dm_cache_policy_get_name); 152c6b4fcbaSJoe Thornber 153*4e7f506fSMike Snitzer const unsigned *dm_cache_policy_get_version(struct dm_cache_policy *p) 154*4e7f506fSMike Snitzer { 155*4e7f506fSMike Snitzer struct dm_cache_policy_type *t = p->private; 156*4e7f506fSMike Snitzer 157*4e7f506fSMike Snitzer return t->version; 158*4e7f506fSMike Snitzer } 159*4e7f506fSMike Snitzer EXPORT_SYMBOL_GPL(dm_cache_policy_get_version); 160*4e7f506fSMike Snitzer 161c6b4fcbaSJoe Thornber size_t dm_cache_policy_get_hint_size(struct dm_cache_policy *p) 162c6b4fcbaSJoe Thornber { 163c6b4fcbaSJoe Thornber struct dm_cache_policy_type *t = p->private; 164c6b4fcbaSJoe Thornber 165c6b4fcbaSJoe Thornber return t->hint_size; 166c6b4fcbaSJoe Thornber } 167c6b4fcbaSJoe Thornber EXPORT_SYMBOL_GPL(dm_cache_policy_get_hint_size); 168c6b4fcbaSJoe Thornber 169c6b4fcbaSJoe Thornber /*----------------------------------------------------------------*/ 170