xref: /openbmc/linux/drivers/md/dm-cache-policy.c (revision 4e7f506f6429636115e2f58f9f97089acc62524a)
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, &register_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(&register_lock);
48c6b4fcbaSJoe Thornber 	t = __get_policy_once(name);
49c6b4fcbaSJoe Thornber 	spin_unlock(&register_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(&register_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, &register_list);
95c6b4fcbaSJoe Thornber 		r = 0;
96c6b4fcbaSJoe Thornber 	}
97c6b4fcbaSJoe Thornber 	spin_unlock(&register_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(&register_lock);
106c6b4fcbaSJoe Thornber 	list_del_init(&type->list);
107c6b4fcbaSJoe Thornber 	spin_unlock(&register_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