Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : #include <linux/module.h>
3 : #include <linux/blkdev.h>
4 : #include <linux/bio.h>
5 :
6 : #include "../dm-core.h"
7 : #include "cache_dev.h"
8 : #include "backing_dev.h"
9 : #include "cache.h"
10 : #include "dm_pcache.h"
11 :
12 1219044 : void pcache_defer_reqs_kick(struct dm_pcache *pcache)
13 : {
14 1219044 : struct pcache_cache *cache = &pcache->cache;
15 :
16 1219044 : spin_lock(&cache->seg_map_lock);
17 1219044 : if (!cache->cache_full)
18 78843 : queue_work(pcache->task_wq, &pcache->defered_req_work);
19 1219044 : spin_unlock(&cache->seg_map_lock);
20 1219044 : }
21 :
22 1140178 : static void defer_req(struct pcache_request *pcache_req)
23 : {
24 1140178 : struct dm_pcache *pcache = pcache_req->pcache;
25 :
26 1140178 : BUG_ON(!list_empty(&pcache_req->list_node));
27 :
28 1140178 : spin_lock(&pcache->defered_req_list_lock);
29 1140201 : list_add(&pcache_req->list_node, &pcache->defered_req_list);
30 1140201 : pcache_defer_reqs_kick(pcache);
31 1140201 : spin_unlock(&pcache->defered_req_list_lock);
32 1140201 : }
33 :
34 38345 : static void defered_req_fn(struct work_struct *work)
35 : {
36 38345 : struct dm_pcache *pcache = container_of(work, struct dm_pcache, defered_req_work);
37 38345 : struct pcache_request *pcache_req;
38 38345 : LIST_HEAD(tmp_list);
39 38345 : int ret;
40 :
41 38345 : if (pcache_is_stopping(pcache))
42 0 : return;
43 :
44 38345 : spin_lock(&pcache->defered_req_list_lock);
45 38345 : list_splice_init(&pcache->defered_req_list, &tmp_list);
46 38345 : spin_unlock(&pcache->defered_req_list_lock);
47 :
48 1216891 : while (!list_empty(&tmp_list)) {
49 1140201 : pcache_req = list_first_entry(&tmp_list,
50 : struct pcache_request, list_node);
51 1140201 : list_del_init(&pcache_req->list_node);
52 1140201 : pcache_req->ret = 0;
53 1140201 : ret = pcache_cache_handle_req(&pcache->cache, pcache_req);
54 1140201 : if (ret == -EBUSY)
55 31418 : defer_req(pcache_req);
56 : else
57 1108783 : pcache_req_put(pcache_req, ret);
58 : }
59 : }
60 :
61 907814 : void pcache_req_get(struct pcache_request *pcache_req)
62 : {
63 907814 : kref_get(&pcache_req->ref);
64 907943 : }
65 :
66 55381079 : static void end_req(struct kref *ref)
67 : {
68 55381079 : struct pcache_request *pcache_req = container_of(ref, struct pcache_request, ref);
69 55381079 : struct bio *bio = pcache_req->bio;
70 55381079 : int ret = pcache_req->ret;
71 :
72 55381079 : if (ret == -EBUSY) {
73 0 : pcache_req_get(pcache_req);
74 0 : defer_req(pcache_req);
75 : } else {
76 55381079 : bio->bi_status = errno_to_blk_status(ret);
77 55399181 : bio_endio(bio);
78 : }
79 55490477 : }
80 :
81 55935391 : void pcache_req_put(struct pcache_request *pcache_req, int ret)
82 : {
83 : /* Set the return status if it is not already set */
84 55935391 : if (ret && !pcache_req->ret)
85 8 : pcache_req->ret = ret;
86 :
87 55935391 : kref_put(&pcache_req->ref, end_req);
88 0 : }
89 :
90 926 : static bool at_least_one_arg(struct dm_arg_set *as, char **error)
91 : {
92 926 : if (!as->argc) {
93 0 : *error = "Insufficient args";
94 0 : return false;
95 : }
96 :
97 : return true;
98 : }
99 :
100 463 : static int parse_cache_dev(struct dm_pcache *pcache, struct dm_arg_set *as,
101 : char **error)
102 : {
103 463 : int ret;
104 :
105 463 : if (!at_least_one_arg(as, error))
106 0 : return -EINVAL;
107 463 : ret = dm_get_device(pcache->ti, dm_shift_arg(as),
108 : BLK_OPEN_READ | BLK_OPEN_WRITE,
109 : &pcache->cache_dev.dm_dev);
110 463 : if (ret) {
111 0 : *error = "Error opening cache device";
112 0 : return ret;
113 : }
114 :
115 : return 0;
116 : }
117 :
118 463 : static int parse_backing_dev(struct dm_pcache *pcache, struct dm_arg_set *as,
119 : char **error)
120 : {
121 463 : int ret;
122 :
123 463 : if (!at_least_one_arg(as, error))
124 0 : return -EINVAL;
125 :
126 463 : ret = dm_get_device(pcache->ti, dm_shift_arg(as),
127 : BLK_OPEN_READ | BLK_OPEN_WRITE,
128 : &pcache->backing_dev.dm_dev);
129 463 : if (ret) {
130 0 : *error = "Error opening backing device";
131 0 : return ret;
132 : }
133 :
134 : return 0;
135 : }
136 :
137 463 : static void pcache_init_opts(struct pcache_cache_options *opts)
138 : {
139 463 : opts->cache_mode = PCACHE_CACHE_MODE_WRITEBACK;
140 463 : opts->data_crc = false;
141 : }
142 :
143 463 : static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as,
144 : char **error)
145 : {
146 463 : struct pcache_cache_options *opts = &pcache->opts;
147 463 : static const struct dm_arg _args[] = {
148 : {0, 4, "Invalid number of cache option arguments"},
149 : };
150 463 : unsigned int argc;
151 463 : const char *arg;
152 463 : int ret;
153 :
154 463 : pcache_init_opts(opts);
155 463 : if (!as->argc)
156 : return 0;
157 :
158 458 : ret = dm_read_arg_group(_args, as, &argc, error);
159 458 : if (ret)
160 : return -EINVAL;
161 :
162 1039 : while (argc) {
163 736 : arg = dm_shift_arg(as);
164 736 : argc--;
165 :
166 736 : if (!strcmp(arg, "cache_mode")) {
167 433 : arg = dm_shift_arg(as);
168 433 : if (!strcmp(arg, "writeback")) {
169 303 : opts->cache_mode = PCACHE_CACHE_MODE_WRITEBACK;
170 : } else {
171 130 : *error = "Invalid cache mode parameter";
172 130 : return -EINVAL;
173 : }
174 303 : argc--;
175 303 : } else if (!strcmp(arg, "data_crc")) {
176 303 : arg = dm_shift_arg(as);
177 303 : if (!strcmp(arg, "true")) {
178 148 : opts->data_crc = true;
179 155 : } else if (!strcmp(arg, "false")) {
180 150 : opts->data_crc = false;
181 : } else {
182 5 : *error = "Invalid data crc parameter";
183 5 : return -EINVAL;
184 : }
185 298 : argc--;
186 : } else {
187 0 : *error = "Unrecognised cache option requested";
188 0 : return -EINVAL;
189 : }
190 : }
191 :
192 : return 0;
193 : }
194 :
195 308 : static int pcache_start(struct dm_pcache *pcache, char **error)
196 : {
197 308 : int ret;
198 :
199 308 : ret = cache_dev_start(pcache);
200 308 : if (ret) {
201 0 : *error = "Failed to start cache dev";
202 0 : return ret;
203 : }
204 :
205 308 : ret = backing_dev_start(pcache);
206 308 : if (ret) {
207 0 : *error = "Failed to start backing dev";
208 0 : goto stop_cache;
209 : }
210 :
211 308 : ret = pcache_cache_start(pcache);
212 308 : if (ret) {
213 5 : *error = "Failed to start pcache";
214 5 : goto stop_backing;
215 : }
216 :
217 : return 0;
218 5 : stop_backing:
219 5 : backing_dev_stop(pcache);
220 5 : stop_cache:
221 5 : cache_dev_stop(pcache);
222 :
223 5 : return ret;
224 : }
225 :
226 465 : static void pcache_destroy_args(struct dm_pcache *pcache)
227 : {
228 465 : if (pcache->cache_dev.dm_dev)
229 465 : dm_put_device(pcache->ti, pcache->cache_dev.dm_dev);
230 465 : if (pcache->backing_dev.dm_dev)
231 465 : dm_put_device(pcache->ti, pcache->backing_dev.dm_dev);
232 465 : }
233 :
234 463 : static int pcache_parse_args(struct dm_pcache *pcache, unsigned int argc, char **argv,
235 : char **error)
236 : {
237 463 : struct dm_arg_set as;
238 463 : int ret;
239 :
240 463 : as.argc = argc;
241 463 : as.argv = argv;
242 :
243 : /*
244 : * Parse cache device
245 : */
246 463 : ret = parse_cache_dev(pcache, &as, error);
247 463 : if (ret)
248 : return ret;
249 : /*
250 : * Parse backing device
251 : */
252 463 : ret = parse_backing_dev(pcache, &as, error);
253 463 : if (ret)
254 0 : goto out;
255 : /*
256 : * Parse optional arguments
257 : */
258 463 : ret = parse_cache_opts(pcache, &as, error);
259 463 : if (ret)
260 155 : goto out;
261 :
262 : return 0;
263 155 : out:
264 155 : pcache_destroy_args(pcache);
265 155 : return ret;
266 : }
267 :
268 469 : static int dm_pcache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
269 : {
270 469 : struct mapped_device *md = ti->table->md;
271 469 : struct dm_pcache *pcache;
272 469 : int ret;
273 :
274 469 : if (md->map) {
275 6 : ti->error = "Don't support table loading for live md";
276 6 : return -EOPNOTSUPP;
277 : }
278 :
279 : /* Allocate memory for the cache structure */
280 463 : pcache = kzalloc(sizeof(struct dm_pcache), GFP_KERNEL);
281 463 : if (!pcache)
282 : return -ENOMEM;
283 :
284 926 : pcache->task_wq = alloc_workqueue("pcache-%s-wq", WQ_UNBOUND | WQ_MEM_RECLAIM,
285 463 : 0, md->name);
286 463 : if (!pcache->task_wq) {
287 0 : ret = -ENOMEM;
288 0 : goto free_pcache;
289 : }
290 :
291 463 : spin_lock_init(&pcache->defered_req_list_lock);
292 463 : INIT_LIST_HEAD(&pcache->defered_req_list);
293 463 : INIT_WORK(&pcache->defered_req_work, defered_req_fn);
294 463 : pcache->ti = ti;
295 :
296 463 : ret = pcache_parse_args(pcache, argc, argv, &ti->error);
297 463 : if (ret)
298 155 : goto destroy_wq;
299 :
300 308 : ret = pcache_start(pcache, &ti->error);
301 308 : if (ret)
302 5 : goto destroy_args;
303 :
304 303 : ti->num_flush_bios = 1;
305 303 : ti->flush_supported = true;
306 303 : ti->per_io_data_size = sizeof(struct pcache_request);
307 303 : ti->private = pcache;
308 303 : atomic_set(&pcache->state, PCACHE_STATE_RUNNING);
309 :
310 303 : return 0;
311 5 : destroy_args:
312 5 : pcache_destroy_args(pcache);
313 160 : destroy_wq:
314 160 : destroy_workqueue(pcache->task_wq);
315 160 : free_pcache:
316 160 : kfree(pcache);
317 :
318 160 : return ret;
319 : }
320 :
321 305 : static void defer_req_stop(struct dm_pcache *pcache)
322 : {
323 305 : struct pcache_request *pcache_req;
324 305 : LIST_HEAD(tmp_list);
325 :
326 305 : flush_work(&pcache->defered_req_work);
327 :
328 305 : spin_lock(&pcache->defered_req_list_lock);
329 305 : list_splice_init(&pcache->defered_req_list, &tmp_list);
330 305 : spin_unlock(&pcache->defered_req_list_lock);
331 :
332 610 : while (!list_empty(&tmp_list)) {
333 0 : pcache_req = list_first_entry(&tmp_list,
334 : struct pcache_request, list_node);
335 0 : list_del_init(&pcache_req->list_node);
336 0 : pcache_req_put(pcache_req, -EIO);
337 : }
338 305 : }
339 :
340 305 : static void dm_pcache_dtr(struct dm_target *ti)
341 : {
342 305 : struct dm_pcache *pcache;
343 :
344 305 : pcache = ti->private;
345 :
346 305 : atomic_set(&pcache->state, PCACHE_STATE_STOPPING);
347 :
348 305 : defer_req_stop(pcache);
349 305 : pcache_cache_stop(pcache);
350 305 : backing_dev_stop(pcache);
351 305 : cache_dev_stop(pcache);
352 :
353 305 : pcache_destroy_args(pcache);
354 305 : drain_workqueue(pcache->task_wq);
355 305 : destroy_workqueue(pcache->task_wq);
356 :
357 305 : kfree(pcache);
358 305 : }
359 :
360 55477005 : static int dm_pcache_map_bio(struct dm_target *ti, struct bio *bio)
361 : {
362 55477005 : struct pcache_request *pcache_req = dm_per_bio_data(bio, sizeof(struct pcache_request));
363 55475788 : struct dm_pcache *pcache = ti->private;
364 55475788 : int ret;
365 :
366 55475788 : pcache_req->pcache = pcache;
367 55475788 : kref_init(&pcache_req->ref);
368 55475788 : pcache_req->ret = 0;
369 55475788 : pcache_req->bio = bio;
370 55475788 : pcache_req->off = (u64)bio->bi_iter.bi_sector << SECTOR_SHIFT;
371 55475788 : pcache_req->data_len = bio->bi_iter.bi_size;
372 55475788 : INIT_LIST_HEAD(&pcache_req->list_node);
373 :
374 55475788 : ret = pcache_cache_handle_req(&pcache->cache, pcache_req);
375 55041709 : if (ret == -EBUSY)
376 1108770 : defer_req(pcache_req);
377 : else
378 53932939 : pcache_req_put(pcache_req, ret);
379 :
380 55345173 : return DM_MAPIO_SUBMITTED;
381 : }
382 :
383 1021 : static void dm_pcache_status(struct dm_target *ti, status_type_t type,
384 : unsigned int status_flags, char *result,
385 : unsigned int maxlen)
386 : {
387 1021 : struct dm_pcache *pcache = ti->private;
388 1021 : struct pcache_cache_dev *cache_dev = &pcache->cache_dev;
389 1021 : struct pcache_backing_dev *backing_dev = &pcache->backing_dev;
390 1021 : struct pcache_cache *cache = &pcache->cache;
391 1021 : unsigned int sz = 0;
392 :
393 1021 : switch (type) {
394 78 : case STATUSTYPE_INFO:
395 156 : DMEMIT("%x %u %u %u %u %x %u:%u %u:%u %u:%u",
396 : cache_dev->sb_flags,
397 : cache_dev->seg_num,
398 : cache->n_segs,
399 : bitmap_weight(cache->seg_map, cache->n_segs),
400 : pcache_cache_get_gc_percent(cache),
401 : cache->cache_info.flags,
402 : cache->key_head.cache_seg->cache_seg_id,
403 : cache->key_head.seg_off,
404 : cache->dirty_tail.cache_seg->cache_seg_id,
405 : cache->dirty_tail.seg_off,
406 : cache->key_tail.cache_seg->cache_seg_id,
407 : cache->key_tail.seg_off);
408 78 : break;
409 640 : case STATUSTYPE_TABLE:
410 954 : DMEMIT("%s %s 4 cache_mode writeback crc %s",
411 : cache_dev->dm_dev->name,
412 : backing_dev->dm_dev->name,
413 : cache_data_crc_on(cache) ? "true" : "false");
414 640 : break;
415 303 : case STATUSTYPE_IMA:
416 303 : *result = '\0';
417 303 : break;
418 : }
419 1021 : }
420 :
421 104 : static int dm_pcache_message(struct dm_target *ti, unsigned int argc,
422 : char **argv, char *result, unsigned int maxlen)
423 : {
424 104 : struct dm_pcache *pcache = ti->private;
425 104 : unsigned long val;
426 :
427 104 : if (argc != 2)
428 6 : goto err;
429 :
430 98 : if (!strcasecmp(argv[0], "gc_percent")) {
431 92 : if (kstrtoul(argv[1], 10, &val))
432 6 : goto err;
433 :
434 86 : return pcache_cache_set_gc_percent(&pcache->cache, val);
435 : }
436 6 : err:
437 : return -EINVAL;
438 : }
439 :
440 : static struct target_type dm_pcache_target = {
441 : .name = "pcache",
442 : .version = {0, 1, 0},
443 : .module = THIS_MODULE,
444 : .features = DM_TARGET_SINGLETON,
445 : .ctr = dm_pcache_ctr,
446 : .dtr = dm_pcache_dtr,
447 : .map = dm_pcache_map_bio,
448 : .status = dm_pcache_status,
449 : .message = dm_pcache_message,
450 : };
451 :
452 289 : static int __init dm_pcache_init(void)
453 : {
454 289 : int ret;
455 :
456 289 : ret = pcache_backing_init();
457 289 : if (ret)
458 0 : goto err;
459 :
460 289 : ret = pcache_cache_init();
461 289 : if (ret)
462 0 : goto backing_exit;
463 :
464 289 : ret = dm_register_target(&dm_pcache_target);
465 289 : if (ret)
466 0 : goto cache_exit;
467 : return 0;
468 :
469 0 : cache_exit:
470 0 : pcache_cache_exit();
471 0 : backing_exit:
472 0 : pcache_backing_exit();
473 : err:
474 : return ret;
475 : }
476 : module_init(dm_pcache_init);
477 :
478 165 : static void __exit dm_pcache_exit(void)
479 : {
480 165 : dm_unregister_target(&dm_pcache_target);
481 165 : pcache_cache_exit();
482 165 : pcache_backing_exit();
483 165 : }
484 : module_exit(dm_pcache_exit);
485 :
486 : MODULE_DESCRIPTION("dm-pcache Persistent Cache for block device");
487 : MODULE_AUTHOR("Dongsheng Yang <dongsheng.yang@linux.dev>");
488 : MODULE_LICENSE("GPL");
|