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