xref: /dflybsd-src/sys/dev/disk/dm/delay/dm_target_delay.c (revision b0a9540a74bf0068ba798f91d02dbab25eed2b90)
1f603807bSTomohiro Kusumi /*
2f603807bSTomohiro Kusumi  * Copyright (c) 2015 The DragonFly Project.  All rights reserved.
3f603807bSTomohiro Kusumi  *
4f603807bSTomohiro Kusumi  * This code is derived from software contributed to The DragonFly Project
5*b0a9540aSTomohiro Kusumi  * by Tomohiro Kusumi <tkusumi@netbsd.org>
6f603807bSTomohiro Kusumi  *
7f603807bSTomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
8f603807bSTomohiro Kusumi  * modification, are permitted provided that the following conditions
9f603807bSTomohiro Kusumi  * are met:
10f603807bSTomohiro Kusumi  *
11f603807bSTomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
12f603807bSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
13f603807bSTomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
14f603807bSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in
15f603807bSTomohiro Kusumi  *    the documentation and/or other materials provided with the
16f603807bSTomohiro Kusumi  *    distribution.
17f603807bSTomohiro Kusumi  * 3. Neither the name of The DragonFly Project nor the names of its
18f603807bSTomohiro Kusumi  *    contributors may be used to endorse or promote products derived
19f603807bSTomohiro Kusumi  *    from this software without specific, prior written permission.
20f603807bSTomohiro Kusumi  *
21f603807bSTomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22f603807bSTomohiro Kusumi  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23f603807bSTomohiro Kusumi  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24f603807bSTomohiro Kusumi  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25f603807bSTomohiro Kusumi  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26f603807bSTomohiro Kusumi  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27f603807bSTomohiro Kusumi  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28f603807bSTomohiro Kusumi  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29f603807bSTomohiro Kusumi  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30f603807bSTomohiro Kusumi  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31f603807bSTomohiro Kusumi  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32f603807bSTomohiro Kusumi  * SUCH DAMAGE.
33f603807bSTomohiro Kusumi  */
34f603807bSTomohiro Kusumi 
35dae65060Szrj #include <sys/param.h>
36dae65060Szrj #include <sys/malloc.h>
37f603807bSTomohiro Kusumi #include <sys/mutex2.h>
38f603807bSTomohiro Kusumi #include <sys/objcache.h>
39f603807bSTomohiro Kusumi #include <sys/callout.h>
40f603807bSTomohiro Kusumi 
41f603807bSTomohiro Kusumi #include <dev/disk/dm/dm.h>
42f603807bSTomohiro Kusumi 
43f603807bSTomohiro Kusumi MALLOC_DEFINE(M_DMDELAY, "dm_delay", "Device Mapper Target Delay");
44f603807bSTomohiro Kusumi 
45f603807bSTomohiro Kusumi struct dm_delay_buf {
46f603807bSTomohiro Kusumi 	TAILQ_ENTRY(dm_delay_buf) entry;
47f603807bSTomohiro Kusumi 	struct buf *bp;
48f603807bSTomohiro Kusumi 	int expire;
49f603807bSTomohiro Kusumi };
50f603807bSTomohiro Kusumi TAILQ_HEAD(dm_delay_buf_list, dm_delay_buf);
51f603807bSTomohiro Kusumi 
52f603807bSTomohiro Kusumi struct dm_delay_info {
53f603807bSTomohiro Kusumi 	dm_pdev_t *pdev;
54f603807bSTomohiro Kusumi 	uint64_t offset;
55f603807bSTomohiro Kusumi 	int delay;
56f603807bSTomohiro Kusumi 	int count;
57f603807bSTomohiro Kusumi 	int enabled;
58f603807bSTomohiro Kusumi 	struct dm_delay_buf_list buf_list;
59f603807bSTomohiro Kusumi 	struct callout cal;
60f603807bSTomohiro Kusumi 	struct mtx buf_mtx;
61f603807bSTomohiro Kusumi 	struct mtx cal_mtx;
62f603807bSTomohiro Kusumi 	struct lwkt_token token;
63f603807bSTomohiro Kusumi 	thread_t td;
64f603807bSTomohiro Kusumi };
65f603807bSTomohiro Kusumi 
66f603807bSTomohiro Kusumi typedef struct target_delay_config {
67f603807bSTomohiro Kusumi 	struct dm_delay_info read;
68f603807bSTomohiro Kusumi 	struct dm_delay_info write;
69f603807bSTomohiro Kusumi 	int argc;  /* either 3 or 6 */
70f603807bSTomohiro Kusumi } dm_target_delay_config_t;
71f603807bSTomohiro Kusumi 
72f603807bSTomohiro Kusumi static int _init(struct dm_delay_info*, char**, int);
73f603807bSTomohiro Kusumi static int _table(struct dm_delay_info*, char*);
74f603807bSTomohiro Kusumi static void _strategy(struct dm_delay_info*, struct buf*);
75f603807bSTomohiro Kusumi static __inline void _submit(struct dm_delay_info*, struct buf*);
76f603807bSTomohiro Kusumi static void _submit_queue(struct dm_delay_info*, int);
77f603807bSTomohiro Kusumi static void _destroy(struct dm_delay_info*);
78f603807bSTomohiro Kusumi static void _timeout(void*);
79f603807bSTomohiro Kusumi static void _thread(void*);
80f603807bSTomohiro Kusumi static __inline void _debug(struct dm_delay_info*, const char*);
81f603807bSTomohiro Kusumi 
82f603807bSTomohiro Kusumi static struct objcache *obj_cache = NULL;
83f603807bSTomohiro Kusumi static struct objcache_malloc_args obj_args = {
84f603807bSTomohiro Kusumi 	sizeof(struct dm_delay_buf), M_DMDELAY,
85f603807bSTomohiro Kusumi };
86f603807bSTomohiro Kusumi 
87f603807bSTomohiro Kusumi static int
dm_target_delay_init(dm_table_entry_t * table_en,int argc,char ** argv)88f603807bSTomohiro Kusumi dm_target_delay_init(dm_table_entry_t *table_en, int argc, char **argv)
89f603807bSTomohiro Kusumi {
90f603807bSTomohiro Kusumi 	dm_target_delay_config_t *tdc;
91f603807bSTomohiro Kusumi 	int ret;
92f603807bSTomohiro Kusumi 
93f603807bSTomohiro Kusumi 	dmdebug("Delay target init: argc=%d\n", argc);
94f603807bSTomohiro Kusumi 	if (argc != 3 && argc != 6) {
95f603807bSTomohiro Kusumi 		kprintf("Delay target takes 3 or 6 args\n");
96f603807bSTomohiro Kusumi 		return EINVAL;
97f603807bSTomohiro Kusumi 	}
98f603807bSTomohiro Kusumi 
99f603807bSTomohiro Kusumi 	tdc = kmalloc(sizeof(*tdc), M_DMDELAY, M_WAITOK | M_ZERO);
100f603807bSTomohiro Kusumi 	if (tdc == NULL)
101f603807bSTomohiro Kusumi 		return ENOMEM;
102f603807bSTomohiro Kusumi 	tdc->argc = argc;
103f603807bSTomohiro Kusumi 
104f603807bSTomohiro Kusumi 	ret = _init(&tdc->read, argv, 0);
105f603807bSTomohiro Kusumi 	if (ret) {
106f603807bSTomohiro Kusumi 		kfree(tdc, M_DMDELAY);
107f603807bSTomohiro Kusumi 		return ret;
108f603807bSTomohiro Kusumi 	}
109f603807bSTomohiro Kusumi 
110f603807bSTomohiro Kusumi 	if (argc == 6)
111f603807bSTomohiro Kusumi 		argv += 3;
112f603807bSTomohiro Kusumi 
113f603807bSTomohiro Kusumi 	ret = _init(&tdc->write, argv, 1);
114f603807bSTomohiro Kusumi 	if (ret) {
115f603807bSTomohiro Kusumi 		dm_pdev_decr(tdc->read.pdev);
116f603807bSTomohiro Kusumi 		kfree(tdc, M_DMDELAY);
117f603807bSTomohiro Kusumi 		return ret;
118f603807bSTomohiro Kusumi 	}
119f603807bSTomohiro Kusumi 
120f603807bSTomohiro Kusumi 	dm_table_add_deps(table_en, tdc->read.pdev);
121f603807bSTomohiro Kusumi 	dm_table_add_deps(table_en, tdc->write.pdev);
122f603807bSTomohiro Kusumi 
12341a68322STomohiro Kusumi 	dm_table_init_target(table_en, tdc);
124f603807bSTomohiro Kusumi 
125f603807bSTomohiro Kusumi 	return 0;
126f603807bSTomohiro Kusumi }
127f603807bSTomohiro Kusumi 
128f603807bSTomohiro Kusumi static int
_init(struct dm_delay_info * di,char ** argv,int id)129f603807bSTomohiro Kusumi _init(struct dm_delay_info *di, char **argv, int id)
130f603807bSTomohiro Kusumi {
131f603807bSTomohiro Kusumi 	dm_pdev_t *dmp;
132f603807bSTomohiro Kusumi 	int tmp;
133f603807bSTomohiro Kusumi 
134f603807bSTomohiro Kusumi 	if (argv[0] == NULL)
135f603807bSTomohiro Kusumi 		return EINVAL;
136f603807bSTomohiro Kusumi 	if ((dmp = dm_pdev_insert(argv[0])) == NULL)
137f603807bSTomohiro Kusumi 		return ENOENT;
138f603807bSTomohiro Kusumi 
139f603807bSTomohiro Kusumi 	di->pdev = dmp;
140f603807bSTomohiro Kusumi 	di->offset = atoi64(argv[1]);
141f603807bSTomohiro Kusumi 	tmp = atoi64(argv[2]);
142f603807bSTomohiro Kusumi 	di->delay = tmp * hz / 1000;
143f603807bSTomohiro Kusumi 	di->count = 0;
144f603807bSTomohiro Kusumi 
145f603807bSTomohiro Kusumi 	TAILQ_INIT(&di->buf_list);
146f603807bSTomohiro Kusumi 	callout_init(&di->cal);
147f603807bSTomohiro Kusumi 	mtx_init(&di->buf_mtx, "dmdlbuf");
148f603807bSTomohiro Kusumi 	mtx_init(&di->cal_mtx, "dmdlcal");
149f603807bSTomohiro Kusumi 	lwkt_token_init(&di->token, "dmdlthr");
150f603807bSTomohiro Kusumi 
151f603807bSTomohiro Kusumi 	di->enabled = 1;
152f603807bSTomohiro Kusumi 	lwkt_create(_thread, di, &di->td, NULL, 0, -1, "dmdl%d", id);
153f603807bSTomohiro Kusumi 
154f603807bSTomohiro Kusumi 	_debug(di, "init");
155f603807bSTomohiro Kusumi 	return 0;
156f603807bSTomohiro Kusumi }
157f603807bSTomohiro Kusumi 
158f603807bSTomohiro Kusumi static char *
dm_target_delay_info(void * target_config)159f603807bSTomohiro Kusumi dm_target_delay_info(void *target_config)
160f603807bSTomohiro Kusumi {
161f603807bSTomohiro Kusumi 	dm_target_delay_config_t *tdc;
162f603807bSTomohiro Kusumi 	char *params;
163f603807bSTomohiro Kusumi 
164f603807bSTomohiro Kusumi 	tdc = target_config;
165f603807bSTomohiro Kusumi 	KKASSERT(tdc != NULL);
166f603807bSTomohiro Kusumi 
167f603807bSTomohiro Kusumi 	params = dm_alloc_string(DM_MAX_PARAMS_SIZE);
168f603807bSTomohiro Kusumi 	ksnprintf(params, DM_MAX_PARAMS_SIZE,
169f603807bSTomohiro Kusumi 		"%d %d", tdc->read.count, tdc->write.count);
170f603807bSTomohiro Kusumi 
171f603807bSTomohiro Kusumi 	return params;
172f603807bSTomohiro Kusumi }
173f603807bSTomohiro Kusumi 
174f603807bSTomohiro Kusumi static char *
dm_target_delay_table(void * target_config)175f603807bSTomohiro Kusumi dm_target_delay_table(void *target_config)
176f603807bSTomohiro Kusumi {
177f603807bSTomohiro Kusumi 	dm_target_delay_config_t *tdc;
178f603807bSTomohiro Kusumi 	char *params, *p;
179f603807bSTomohiro Kusumi 
180f603807bSTomohiro Kusumi 	tdc = target_config;
181f603807bSTomohiro Kusumi 	KKASSERT(tdc != NULL);
182f603807bSTomohiro Kusumi 
183f603807bSTomohiro Kusumi 	params = dm_alloc_string(DM_MAX_PARAMS_SIZE);
184f603807bSTomohiro Kusumi 	p = params;
185f603807bSTomohiro Kusumi 	p += _table(&tdc->read, p);
186f603807bSTomohiro Kusumi 	if (tdc->argc == 6) {
187f603807bSTomohiro Kusumi 		p += ksnprintf(p, DM_MAX_PARAMS_SIZE, " ");
188f603807bSTomohiro Kusumi 		_table(&tdc->write, p);
189f603807bSTomohiro Kusumi 	}
190f603807bSTomohiro Kusumi 
191f603807bSTomohiro Kusumi 	return params;
192f603807bSTomohiro Kusumi }
193f603807bSTomohiro Kusumi 
_table(struct dm_delay_info * di,char * p)194f603807bSTomohiro Kusumi static int _table(struct dm_delay_info *di, char *p)
195f603807bSTomohiro Kusumi {
196f603807bSTomohiro Kusumi 	int ret;
197f603807bSTomohiro Kusumi 
198f603807bSTomohiro Kusumi 	ret = ksnprintf(p, DM_MAX_PARAMS_SIZE,
199f603807bSTomohiro Kusumi 		"%s %" PRIu64 " %d",
200f603807bSTomohiro Kusumi 		di->pdev->udev_name, di->offset, di->delay);
201f603807bSTomohiro Kusumi 	return ret;
202f603807bSTomohiro Kusumi }
203f603807bSTomohiro Kusumi 
204f603807bSTomohiro Kusumi static int
dm_target_delay_strategy(dm_table_entry_t * table_en,struct buf * bp)205f603807bSTomohiro Kusumi dm_target_delay_strategy(dm_table_entry_t *table_en, struct buf *bp)
206f603807bSTomohiro Kusumi {
207f603807bSTomohiro Kusumi 	dm_target_delay_config_t *tdc;
208f603807bSTomohiro Kusumi 	struct dm_delay_info *di;
209f603807bSTomohiro Kusumi 
210f603807bSTomohiro Kusumi 	tdc = table_en->target_config;
211f603807bSTomohiro Kusumi 	KKASSERT(tdc != NULL);
212f603807bSTomohiro Kusumi 
213f603807bSTomohiro Kusumi 	switch (bp->b_cmd) {
214f603807bSTomohiro Kusumi 	case BUF_CMD_READ:
215f603807bSTomohiro Kusumi 		di = &tdc->read;
216f603807bSTomohiro Kusumi 		break;
217f603807bSTomohiro Kusumi 	case BUF_CMD_WRITE:
218f603807bSTomohiro Kusumi 	case BUF_CMD_FLUSH:
219f603807bSTomohiro Kusumi 		di = &tdc->write;
220f603807bSTomohiro Kusumi 		break;
221f603807bSTomohiro Kusumi 	default:
222f603807bSTomohiro Kusumi 		di = NULL;
223f603807bSTomohiro Kusumi 		break;
224f603807bSTomohiro Kusumi 	}
225f603807bSTomohiro Kusumi 
226f603807bSTomohiro Kusumi 	if (di) {
227f603807bSTomohiro Kusumi 		if (di->delay) {
228f603807bSTomohiro Kusumi 			_strategy(di, bp);
229f603807bSTomohiro Kusumi 		} else {
230f603807bSTomohiro Kusumi 			_submit(di, bp);
231f603807bSTomohiro Kusumi 		}
232f603807bSTomohiro Kusumi 	} else {
233f603807bSTomohiro Kusumi 		/* XXX */
234f603807bSTomohiro Kusumi 		struct vnode *vnode = tdc->write.pdev->pdev_vnode;
235f603807bSTomohiro Kusumi 		vn_strategy(vnode, &bp->b_bio1);
236f603807bSTomohiro Kusumi 	}
237f603807bSTomohiro Kusumi 	return 0;
238f603807bSTomohiro Kusumi }
239f603807bSTomohiro Kusumi 
240f603807bSTomohiro Kusumi static void
_strategy(struct dm_delay_info * di,struct buf * bp)241f603807bSTomohiro Kusumi _strategy(struct dm_delay_info *di, struct buf *bp)
242f603807bSTomohiro Kusumi {
243f603807bSTomohiro Kusumi 	struct dm_delay_buf *dp;
244f603807bSTomohiro Kusumi 
245f603807bSTomohiro Kusumi 	dp = objcache_get(obj_cache, M_WAITOK);
246f603807bSTomohiro Kusumi 	dp->bp = bp;
247f603807bSTomohiro Kusumi 	dp->expire = ticks + di->delay;
248f603807bSTomohiro Kusumi 
249f603807bSTomohiro Kusumi 	mtx_lock(&di->buf_mtx);
250f603807bSTomohiro Kusumi 	di->count++;
251f603807bSTomohiro Kusumi 	TAILQ_INSERT_TAIL(&di->buf_list, dp, entry);
252f603807bSTomohiro Kusumi 	mtx_unlock(&di->buf_mtx);
253f603807bSTomohiro Kusumi 
254f603807bSTomohiro Kusumi 	mtx_lock(&di->cal_mtx);
255f603807bSTomohiro Kusumi 	if (!callout_pending(&di->cal))
256f603807bSTomohiro Kusumi 		callout_reset(&di->cal, di->delay, _timeout, di);
257f603807bSTomohiro Kusumi 	mtx_unlock(&di->cal_mtx);
258f603807bSTomohiro Kusumi }
259f603807bSTomohiro Kusumi 
260f603807bSTomohiro Kusumi static __inline
261f603807bSTomohiro Kusumi void
_submit(struct dm_delay_info * di,struct buf * bp)262f603807bSTomohiro Kusumi _submit(struct dm_delay_info *di, struct buf *bp)
263f603807bSTomohiro Kusumi {
264f603807bSTomohiro Kusumi 	_debug(di, "submit");
265f603807bSTomohiro Kusumi 
266f603807bSTomohiro Kusumi 	bp->b_bio1.bio_offset += di->offset * DEV_BSIZE;
267f603807bSTomohiro Kusumi 	vn_strategy(di->pdev->pdev_vnode, &bp->b_bio1);
268f603807bSTomohiro Kusumi }
269f603807bSTomohiro Kusumi 
270f603807bSTomohiro Kusumi static void
_submit_queue(struct dm_delay_info * di,int submit_all)271f603807bSTomohiro Kusumi _submit_queue(struct dm_delay_info *di, int submit_all)
272f603807bSTomohiro Kusumi {
273f603807bSTomohiro Kusumi 	struct dm_delay_buf *dp;
274f603807bSTomohiro Kusumi 	struct dm_delay_buf_list tmp_list;
275f603807bSTomohiro Kusumi 	int next = -1;
276f603807bSTomohiro Kusumi 	int reset = 0;
277f603807bSTomohiro Kusumi 
278f603807bSTomohiro Kusumi 	_debug(di, "submitq");
279f603807bSTomohiro Kusumi 	TAILQ_INIT(&tmp_list);
280f603807bSTomohiro Kusumi 
281f603807bSTomohiro Kusumi 	mtx_lock(&di->buf_mtx);
282f603807bSTomohiro Kusumi 	while ((dp = TAILQ_FIRST(&di->buf_list)) != NULL) {
283f603807bSTomohiro Kusumi 		if (submit_all || ticks > dp->expire) {
284f603807bSTomohiro Kusumi 			TAILQ_REMOVE(&di->buf_list, dp, entry);
285f603807bSTomohiro Kusumi 			TAILQ_INSERT_TAIL(&tmp_list, dp, entry);
286f603807bSTomohiro Kusumi 			di->count--;
287f603807bSTomohiro Kusumi 			continue;
288f603807bSTomohiro Kusumi 		}
289f603807bSTomohiro Kusumi 		if (reset == 0) {
290f603807bSTomohiro Kusumi 			reset = 1;
291f603807bSTomohiro Kusumi 			next = dp->expire;
292f603807bSTomohiro Kusumi 		} else {
293f603807bSTomohiro Kusumi 			next = min(next, dp->expire);
294f603807bSTomohiro Kusumi 		}
295f603807bSTomohiro Kusumi 	}
296f603807bSTomohiro Kusumi 	mtx_unlock(&di->buf_mtx);
297f603807bSTomohiro Kusumi 
298f603807bSTomohiro Kusumi 	if (reset) {
299f603807bSTomohiro Kusumi 		mtx_lock(&di->cal_mtx);
300f603807bSTomohiro Kusumi 		callout_reset(&di->cal, next - ticks, _timeout, di);
301f603807bSTomohiro Kusumi 		mtx_unlock(&di->cal_mtx);
302f603807bSTomohiro Kusumi 	}
303f603807bSTomohiro Kusumi 
304f603807bSTomohiro Kusumi 	while ((dp = TAILQ_FIRST(&tmp_list)) != NULL) {
305f603807bSTomohiro Kusumi 		TAILQ_REMOVE(&tmp_list, dp, entry);
306f603807bSTomohiro Kusumi 		_submit(di, dp->bp);
307f603807bSTomohiro Kusumi 		objcache_put(obj_cache, dp);
308f603807bSTomohiro Kusumi 	}
309f603807bSTomohiro Kusumi }
310f603807bSTomohiro Kusumi 
311f603807bSTomohiro Kusumi static int
dm_target_delay_destroy(dm_table_entry_t * table_en)312f603807bSTomohiro Kusumi dm_target_delay_destroy(dm_table_entry_t *table_en)
313f603807bSTomohiro Kusumi {
314f603807bSTomohiro Kusumi 	dm_target_delay_config_t *tdc;
315f603807bSTomohiro Kusumi 
316f603807bSTomohiro Kusumi 	tdc = table_en->target_config;
317f603807bSTomohiro Kusumi 	if (tdc == NULL)
318f603807bSTomohiro Kusumi 		return 0;
319f603807bSTomohiro Kusumi 
320f603807bSTomohiro Kusumi 	_destroy(&tdc->read);
321f603807bSTomohiro Kusumi 	_destroy(&tdc->write);
322f603807bSTomohiro Kusumi 
323f603807bSTomohiro Kusumi 	kfree(tdc, M_DMDELAY);
324f603807bSTomohiro Kusumi 
325f603807bSTomohiro Kusumi 	return 0;
326f603807bSTomohiro Kusumi }
327f603807bSTomohiro Kusumi 
328f603807bSTomohiro Kusumi static void
_destroy(struct dm_delay_info * di)329f603807bSTomohiro Kusumi _destroy(struct dm_delay_info *di)
330f603807bSTomohiro Kusumi {
331f603807bSTomohiro Kusumi 	_debug(di, "destroy");
332f603807bSTomohiro Kusumi 
333f603807bSTomohiro Kusumi 	lwkt_gettoken(&di->token);
334f603807bSTomohiro Kusumi 	di->enabled = 0;
335f603807bSTomohiro Kusumi 
336f603807bSTomohiro Kusumi 	mtx_lock(&di->cal_mtx);
337f603807bSTomohiro Kusumi 	if (callout_pending(&di->cal))
338eb67213aSMatthew Dillon 		callout_cancel(&di->cal);
339f603807bSTomohiro Kusumi 	mtx_unlock(&di->cal_mtx);
340f603807bSTomohiro Kusumi 
341f603807bSTomohiro Kusumi 	_submit_queue(di, 1);
342f603807bSTomohiro Kusumi 	wakeup(di);
343f603807bSTomohiro Kusumi 	tsleep(&di->enabled, 0, "dmdldestroy", 0);
344f603807bSTomohiro Kusumi 	lwkt_reltoken(&di->token);
345f603807bSTomohiro Kusumi 
346f603807bSTomohiro Kusumi 	mtx_uninit(&di->cal_mtx);
347f603807bSTomohiro Kusumi 	mtx_uninit(&di->buf_mtx);
348f603807bSTomohiro Kusumi 
349f603807bSTomohiro Kusumi 	dm_pdev_decr(di->pdev);
350f603807bSTomohiro Kusumi }
351f603807bSTomohiro Kusumi 
352f603807bSTomohiro Kusumi static void
_timeout(void * arg)353f603807bSTomohiro Kusumi _timeout(void *arg)
354f603807bSTomohiro Kusumi {
355f603807bSTomohiro Kusumi 	struct dm_delay_info *di = arg;
356f603807bSTomohiro Kusumi 
357f603807bSTomohiro Kusumi 	_debug(di, "timeout");
358f603807bSTomohiro Kusumi 	wakeup(di);
359f603807bSTomohiro Kusumi }
360f603807bSTomohiro Kusumi 
361f603807bSTomohiro Kusumi static void
_thread(void * arg)362f603807bSTomohiro Kusumi _thread(void *arg)
363f603807bSTomohiro Kusumi {
364f603807bSTomohiro Kusumi 	struct dm_delay_info *di = arg;
365f603807bSTomohiro Kusumi 
366f603807bSTomohiro Kusumi 	_debug(di, "thread init");
367f603807bSTomohiro Kusumi 	lwkt_gettoken(&di->token);
368f603807bSTomohiro Kusumi 
369f603807bSTomohiro Kusumi 	while (di->enabled) {
370f603807bSTomohiro Kusumi 		tsleep(di, 0, "dmdlthread", 0);
371f603807bSTomohiro Kusumi 		_submit_queue(di, 0);
372f603807bSTomohiro Kusumi 	}
373f603807bSTomohiro Kusumi 
374f603807bSTomohiro Kusumi 	di->td = NULL;
375f603807bSTomohiro Kusumi 	wakeup(&di->enabled);
376f603807bSTomohiro Kusumi 
377f603807bSTomohiro Kusumi 	_debug(di, "thread exit");
378f603807bSTomohiro Kusumi 	lwkt_reltoken(&di->token);
379f603807bSTomohiro Kusumi 	lwkt_exit();
380f603807bSTomohiro Kusumi }
381f603807bSTomohiro Kusumi 
382f603807bSTomohiro Kusumi static __inline
383f603807bSTomohiro Kusumi void
_debug(struct dm_delay_info * di,const char * msg)384f603807bSTomohiro Kusumi _debug(struct dm_delay_info *di, const char *msg)
385f603807bSTomohiro Kusumi {
386f603807bSTomohiro Kusumi 	dmdebug("%-8s: %d pdev=%s offset=%ju delay=%d count=%d\n",
387f603807bSTomohiro Kusumi 		msg, di->enabled, di->pdev->name,
388f603807bSTomohiro Kusumi 		(uintmax_t)di->offset, di->delay, di->count);
389f603807bSTomohiro Kusumi }
390f603807bSTomohiro Kusumi 
391f603807bSTomohiro Kusumi static void
_objcache_create(void)392f603807bSTomohiro Kusumi _objcache_create(void)
393f603807bSTomohiro Kusumi {
394f603807bSTomohiro Kusumi 	if (obj_cache == NULL) {
395f603807bSTomohiro Kusumi 		obj_cache = objcache_create("dmdlobj", 0, 0, NULL, NULL, NULL,
396f603807bSTomohiro Kusumi 			objcache_malloc_alloc,
397f603807bSTomohiro Kusumi 			objcache_malloc_free,
398f603807bSTomohiro Kusumi 			&obj_args);
399f603807bSTomohiro Kusumi 	}
400f603807bSTomohiro Kusumi 	KKASSERT(obj_cache);
401f603807bSTomohiro Kusumi }
402f603807bSTomohiro Kusumi 
403f603807bSTomohiro Kusumi static void
_objcache_destroy(void)404f603807bSTomohiro Kusumi _objcache_destroy(void)
405f603807bSTomohiro Kusumi {
406f603807bSTomohiro Kusumi 	if (obj_cache) {
407f603807bSTomohiro Kusumi 		objcache_destroy(obj_cache);
408f603807bSTomohiro Kusumi 		obj_cache = NULL;
409f603807bSTomohiro Kusumi 	}
410f603807bSTomohiro Kusumi }
411f603807bSTomohiro Kusumi 
412f603807bSTomohiro Kusumi static int
dmtd_mod_handler(module_t mod,int type,void * unused)413f603807bSTomohiro Kusumi dmtd_mod_handler(module_t mod, int type, void *unused)
414f603807bSTomohiro Kusumi {
415f603807bSTomohiro Kusumi 	dm_target_t *dmt = NULL;
416f603807bSTomohiro Kusumi 	int err = 0;
417f603807bSTomohiro Kusumi 
418f603807bSTomohiro Kusumi 	switch(type) {
419f603807bSTomohiro Kusumi 	case MOD_LOAD:
420f603807bSTomohiro Kusumi 		if ((dmt = dm_target_lookup("delay")) != NULL) {
421f603807bSTomohiro Kusumi 			dm_target_unbusy(dmt);
422f603807bSTomohiro Kusumi 			return EEXIST;
423f603807bSTomohiro Kusumi 		}
424f603807bSTomohiro Kusumi 		dmt = dm_target_alloc("delay");
425f603807bSTomohiro Kusumi 		dmt->version[0] = 1;
426f603807bSTomohiro Kusumi 		dmt->version[1] = 0;
427f603807bSTomohiro Kusumi 		dmt->version[2] = 0;
428f603807bSTomohiro Kusumi 		dmt->init = &dm_target_delay_init;
429f603807bSTomohiro Kusumi 		dmt->destroy = &dm_target_delay_destroy;
430f603807bSTomohiro Kusumi 		dmt->strategy = &dm_target_delay_strategy;
431f603807bSTomohiro Kusumi 		dmt->table = &dm_target_delay_table;
432f603807bSTomohiro Kusumi 		dmt->info = &dm_target_delay_info;
433f603807bSTomohiro Kusumi 
434f603807bSTomohiro Kusumi 		_objcache_create();
435f603807bSTomohiro Kusumi 		err = dm_target_insert(dmt);
436f603807bSTomohiro Kusumi 		if (err == 0)
437f603807bSTomohiro Kusumi 			kprintf("dm_target_delay: Successfully initialized\n");
438f603807bSTomohiro Kusumi 		break;
439f603807bSTomohiro Kusumi 
440f603807bSTomohiro Kusumi 	case MOD_UNLOAD:
441f603807bSTomohiro Kusumi 		err = dm_target_remove("delay");
442f603807bSTomohiro Kusumi 		if (err == 0)
443f603807bSTomohiro Kusumi 			kprintf("dm_target_delay: unloaded\n");
444f603807bSTomohiro Kusumi 		_objcache_destroy();
445f603807bSTomohiro Kusumi 		break;
446f603807bSTomohiro Kusumi 	}
447f603807bSTomohiro Kusumi 
448f603807bSTomohiro Kusumi 	return err;
449f603807bSTomohiro Kusumi }
450f603807bSTomohiro Kusumi 
451f603807bSTomohiro Kusumi DM_TARGET_MODULE(dm_target_delay, dmtd_mod_handler);
452