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