aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-cache-policy.c
diff options
context:
space:
mode:
authorJoe Thornber <ejt@redhat.com>2013-03-01 17:45:51 -0500
committerAlasdair G Kergon <agk@redhat.com>2013-03-01 17:45:51 -0500
commitc6b4fcbad044e6fffcc75bba160e720eb8d67d17 (patch)
tree1fb20e6ca157ebfbf2c97ae022fc6ba3e0550dd6 /drivers/md/dm-cache-policy.c
parent7a87edfee75151abb69d47dba2277ff2de0f6071 (diff)
dm: add cache target
Add a target that allows a fast device such as an SSD to be used as a cache for a slower device such as a disk. A plug-in architecture was chosen so that the decisions about which data to migrate and when are delegated to interchangeable tunable policy modules. The first general purpose module we have developed, called "mq" (multiqueue), follows in the next patch. Other modules are under development. Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Heinz Mauelshagen <mauelshagen@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-cache-policy.c')
-rw-r--r--drivers/md/dm-cache-policy.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/drivers/md/dm-cache-policy.c b/drivers/md/dm-cache-policy.c
new file mode 100644
index 000000000000..2cbf5fdaac52
--- /dev/null
+++ b/drivers/md/dm-cache-policy.c
@@ -0,0 +1,161 @@
1/*
2 * Copyright (C) 2012 Red Hat. All rights reserved.
3 *
4 * This file is released under the GPL.
5 */
6
7#include "dm-cache-policy-internal.h"
8#include "dm.h"
9
10#include <linux/module.h>
11#include <linux/slab.h>
12
13/*----------------------------------------------------------------*/
14
15#define DM_MSG_PREFIX "cache-policy"
16
17static DEFINE_SPINLOCK(register_lock);
18static LIST_HEAD(register_list);
19
20static struct dm_cache_policy_type *__find_policy(const char *name)
21{
22 struct dm_cache_policy_type *t;
23
24 list_for_each_entry(t, &register_list, list)
25 if (!strcmp(t->name, name))
26 return t;
27
28 return NULL;
29}
30
31static struct dm_cache_policy_type *__get_policy_once(const char *name)
32{
33 struct dm_cache_policy_type *t = __find_policy(name);
34
35 if (t && !try_module_get(t->owner)) {
36 DMWARN("couldn't get module %s", name);
37 t = ERR_PTR(-EINVAL);
38 }
39
40 return t;
41}
42
43static struct dm_cache_policy_type *get_policy_once(const char *name)
44{
45 struct dm_cache_policy_type *t;
46
47 spin_lock(&register_lock);
48 t = __get_policy_once(name);
49 spin_unlock(&register_lock);
50
51 return t;
52}
53
54static struct dm_cache_policy_type *get_policy(const char *name)
55{
56 struct dm_cache_policy_type *t;
57
58 t = get_policy_once(name);
59 if (IS_ERR(t))
60 return NULL;
61
62 if (t)
63 return t;
64
65 request_module("dm-cache-%s", name);
66
67 t = get_policy_once(name);
68 if (IS_ERR(t))
69 return NULL;
70
71 return t;
72}
73
74static void put_policy(struct dm_cache_policy_type *t)
75{
76 module_put(t->owner);
77}
78
79int dm_cache_policy_register(struct dm_cache_policy_type *type)
80{
81 int r;
82
83 /* One size fits all for now */
84 if (type->hint_size != 0 && type->hint_size != 4) {
85 DMWARN("hint size must be 0 or 4 but %llu supplied.", (unsigned long long) type->hint_size);
86 return -EINVAL;
87 }
88
89 spin_lock(&register_lock);
90 if (__find_policy(type->name)) {
91 DMWARN("attempt to register policy under duplicate name %s", type->name);
92 r = -EINVAL;
93 } else {
94 list_add(&type->list, &register_list);
95 r = 0;
96 }
97 spin_unlock(&register_lock);
98
99 return r;
100}
101EXPORT_SYMBOL_GPL(dm_cache_policy_register);
102
103void dm_cache_policy_unregister(struct dm_cache_policy_type *type)
104{
105 spin_lock(&register_lock);
106 list_del_init(&type->list);
107 spin_unlock(&register_lock);
108}
109EXPORT_SYMBOL_GPL(dm_cache_policy_unregister);
110
111struct dm_cache_policy *dm_cache_policy_create(const char *name,
112 dm_cblock_t cache_size,
113 sector_t origin_size,
114 sector_t cache_block_size)
115{
116 struct dm_cache_policy *p = NULL;
117 struct dm_cache_policy_type *type;
118
119 type = get_policy(name);
120 if (!type) {
121 DMWARN("unknown policy type");
122 return NULL;
123 }
124
125 p = type->create(cache_size, origin_size, cache_block_size);
126 if (!p) {
127 put_policy(type);
128 return NULL;
129 }
130 p->private = type;
131
132 return p;
133}
134EXPORT_SYMBOL_GPL(dm_cache_policy_create);
135
136void dm_cache_policy_destroy(struct dm_cache_policy *p)
137{
138 struct dm_cache_policy_type *t = p->private;
139
140 p->destroy(p);
141 put_policy(t);
142}
143EXPORT_SYMBOL_GPL(dm_cache_policy_destroy);
144
145const char *dm_cache_policy_get_name(struct dm_cache_policy *p)
146{
147 struct dm_cache_policy_type *t = p->private;
148
149 return t->name;
150}
151EXPORT_SYMBOL_GPL(dm_cache_policy_get_name);
152
153size_t dm_cache_policy_get_hint_size(struct dm_cache_policy *p)
154{
155 struct dm_cache_policy_type *t = p->private;
156
157 return t->hint_size;
158}
159EXPORT_SYMBOL_GPL(dm_cache_policy_get_hint_size);
160
161/*----------------------------------------------------------------*/