diff options
Diffstat (limited to 'drivers/md/dm-exception-store.c')
-rw-r--r-- | drivers/md/dm-exception-store.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index dccbfb0e010f..8912a3637cae 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
@@ -14,6 +14,168 @@ | |||
14 | 14 | ||
15 | #define DM_MSG_PREFIX "snapshot exception stores" | 15 | #define DM_MSG_PREFIX "snapshot exception stores" |
16 | 16 | ||
17 | static LIST_HEAD(_exception_store_types); | ||
18 | static DEFINE_SPINLOCK(_lock); | ||
19 | |||
20 | static struct dm_exception_store_type *__find_exception_store_type(const char *name) | ||
21 | { | ||
22 | struct dm_exception_store_type *type; | ||
23 | |||
24 | list_for_each_entry(type, &_exception_store_types, list) | ||
25 | if (!strcmp(name, type->name)) | ||
26 | return type; | ||
27 | |||
28 | return NULL; | ||
29 | } | ||
30 | |||
31 | static struct dm_exception_store_type *_get_exception_store_type(const char *name) | ||
32 | { | ||
33 | struct dm_exception_store_type *type; | ||
34 | |||
35 | spin_lock(&_lock); | ||
36 | |||
37 | type = __find_exception_store_type(name); | ||
38 | |||
39 | if (type && !try_module_get(type->module)) | ||
40 | type = NULL; | ||
41 | |||
42 | spin_unlock(&_lock); | ||
43 | |||
44 | return type; | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * get_type | ||
49 | * @type_name | ||
50 | * | ||
51 | * Attempt to retrieve the dm_exception_store_type by name. If not already | ||
52 | * available, attempt to load the appropriate module. | ||
53 | * | ||
54 | * Exstore modules are named "dm-exstore-" followed by the 'type_name'. | ||
55 | * Modules may contain multiple types. | ||
56 | * This function will first try the module "dm-exstore-<type_name>", | ||
57 | * then truncate 'type_name' on the last '-' and try again. | ||
58 | * | ||
59 | * For example, if type_name was "clustered-shared", it would search | ||
60 | * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'. | ||
61 | * | ||
62 | * 'dm-exception-store-<type_name>' is too long of a name in my | ||
63 | * opinion, which is why I've chosen to have the files | ||
64 | * containing exception store implementations be 'dm-exstore-<type_name>'. | ||
65 | * If you want your module to be autoloaded, you will follow this | ||
66 | * naming convention. | ||
67 | * | ||
68 | * Returns: dm_exception_store_type* on success, NULL on failure | ||
69 | */ | ||
70 | static struct dm_exception_store_type *get_type(const char *type_name) | ||
71 | { | ||
72 | char *p, *type_name_dup; | ||
73 | struct dm_exception_store_type *type; | ||
74 | |||
75 | type = _get_exception_store_type(type_name); | ||
76 | if (type) | ||
77 | return type; | ||
78 | |||
79 | type_name_dup = kstrdup(type_name, GFP_KERNEL); | ||
80 | if (!type_name_dup) { | ||
81 | DMERR("No memory left to attempt load for \"%s\"", type_name); | ||
82 | return NULL; | ||
83 | } | ||
84 | |||
85 | while (request_module("dm-exstore-%s", type_name_dup) || | ||
86 | !(type = _get_exception_store_type(type_name))) { | ||
87 | p = strrchr(type_name_dup, '-'); | ||
88 | if (!p) | ||
89 | break; | ||
90 | p[0] = '\0'; | ||
91 | } | ||
92 | |||
93 | if (!type) | ||
94 | DMWARN("Module for exstore type \"%s\" not found.", type_name); | ||
95 | |||
96 | kfree(type_name_dup); | ||
97 | |||
98 | return type; | ||
99 | } | ||
100 | |||
101 | static void put_type(struct dm_exception_store_type *type) | ||
102 | { | ||
103 | spin_lock(&_lock); | ||
104 | module_put(type->module); | ||
105 | spin_unlock(&_lock); | ||
106 | } | ||
107 | |||
108 | int dm_exception_store_type_register(struct dm_exception_store_type *type) | ||
109 | { | ||
110 | int r = 0; | ||
111 | |||
112 | spin_lock(&_lock); | ||
113 | if (!__find_exception_store_type(type->name)) | ||
114 | list_add(&type->list, &_exception_store_types); | ||
115 | else | ||
116 | r = -EEXIST; | ||
117 | spin_unlock(&_lock); | ||
118 | |||
119 | return r; | ||
120 | } | ||
121 | EXPORT_SYMBOL(dm_exception_store_type_register); | ||
122 | |||
123 | int dm_exception_store_type_unregister(struct dm_exception_store_type *type) | ||
124 | { | ||
125 | spin_lock(&_lock); | ||
126 | |||
127 | if (!__find_exception_store_type(type->name)) { | ||
128 | spin_unlock(&_lock); | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | |||
132 | list_del(&type->list); | ||
133 | |||
134 | spin_unlock(&_lock); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | EXPORT_SYMBOL(dm_exception_store_type_unregister); | ||
139 | |||
140 | int dm_exception_store_create(const char *type_name, | ||
141 | struct dm_exception_store **store) | ||
142 | { | ||
143 | int r = 0; | ||
144 | struct dm_exception_store_type *type; | ||
145 | struct dm_exception_store *tmp_store; | ||
146 | |||
147 | tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); | ||
148 | if (!tmp_store) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | type = get_type(type_name); | ||
152 | if (!type) { | ||
153 | kfree(tmp_store); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | tmp_store->type = type; | ||
158 | |||
159 | r = type->ctr(tmp_store, 0, NULL); | ||
160 | if (r) { | ||
161 | put_type(type); | ||
162 | kfree(tmp_store); | ||
163 | return r; | ||
164 | } | ||
165 | |||
166 | *store = tmp_store; | ||
167 | return 0; | ||
168 | } | ||
169 | EXPORT_SYMBOL(dm_exception_store_create); | ||
170 | |||
171 | void dm_exception_store_destroy(struct dm_exception_store *store) | ||
172 | { | ||
173 | store->type->dtr(store); | ||
174 | put_type(store->type); | ||
175 | kfree(store); | ||
176 | } | ||
177 | EXPORT_SYMBOL(dm_exception_store_destroy); | ||
178 | |||
17 | int dm_exception_store_init(void) | 179 | int dm_exception_store_init(void) |
18 | { | 180 | { |
19 | int r; | 181 | int r; |