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