Root/drivers/md/dm-delay.c

1/*
2 * Copyright (C) 2005-2007 Red Hat GmbH
3 *
4 * A target that delays reads and/or writes and can send
5 * them to different devices.
6 *
7 * This file is released under the GPL.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/blkdev.h>
13#include <linux/bio.h>
14#include <linux/slab.h>
15
16#include <linux/device-mapper.h>
17
18#define DM_MSG_PREFIX "delay"
19
20struct delay_c {
21    struct timer_list delay_timer;
22    struct mutex timer_lock;
23    struct work_struct flush_expired_bios;
24    struct list_head delayed_bios;
25    atomic_t may_delay;
26    mempool_t *delayed_pool;
27
28    struct dm_dev *dev_read;
29    sector_t start_read;
30    unsigned read_delay;
31    unsigned reads;
32
33    struct dm_dev *dev_write;
34    sector_t start_write;
35    unsigned write_delay;
36    unsigned writes;
37};
38
39struct dm_delay_info {
40    struct delay_c *context;
41    struct list_head list;
42    struct bio *bio;
43    unsigned long expires;
44};
45
46static DEFINE_MUTEX(delayed_bios_lock);
47
48static struct workqueue_struct *kdelayd_wq;
49static struct kmem_cache *delayed_cache;
50
51static void handle_delayed_timer(unsigned long data)
52{
53    struct delay_c *dc = (struct delay_c *)data;
54
55    queue_work(kdelayd_wq, &dc->flush_expired_bios);
56}
57
58static void queue_timeout(struct delay_c *dc, unsigned long expires)
59{
60    mutex_lock(&dc->timer_lock);
61
62    if (!timer_pending(&dc->delay_timer) || expires < dc->delay_timer.expires)
63        mod_timer(&dc->delay_timer, expires);
64
65    mutex_unlock(&dc->timer_lock);
66}
67
68static void flush_bios(struct bio *bio)
69{
70    struct bio *n;
71
72    while (bio) {
73        n = bio->bi_next;
74        bio->bi_next = NULL;
75        generic_make_request(bio);
76        bio = n;
77    }
78}
79
80static struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all)
81{
82    struct dm_delay_info *delayed, *next;
83    unsigned long next_expires = 0;
84    int start_timer = 0;
85    struct bio_list flush_bios = { };
86
87    mutex_lock(&delayed_bios_lock);
88    list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
89        if (flush_all || time_after_eq(jiffies, delayed->expires)) {
90            list_del(&delayed->list);
91            bio_list_add(&flush_bios, delayed->bio);
92            if ((bio_data_dir(delayed->bio) == WRITE))
93                delayed->context->writes--;
94            else
95                delayed->context->reads--;
96            mempool_free(delayed, dc->delayed_pool);
97            continue;
98        }
99
100        if (!start_timer) {
101            start_timer = 1;
102            next_expires = delayed->expires;
103        } else
104            next_expires = min(next_expires, delayed->expires);
105    }
106
107    mutex_unlock(&delayed_bios_lock);
108
109    if (start_timer)
110        queue_timeout(dc, next_expires);
111
112    return bio_list_get(&flush_bios);
113}
114
115static void flush_expired_bios(struct work_struct *work)
116{
117    struct delay_c *dc;
118
119    dc = container_of(work, struct delay_c, flush_expired_bios);
120    flush_bios(flush_delayed_bios(dc, 0));
121}
122
123/*
124 * Mapping parameters:
125 * <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
126 *
127 * With separate write parameters, the first set is only used for reads.
128 * Delays are specified in milliseconds.
129 */
130static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
131{
132    struct delay_c *dc;
133    unsigned long long tmpll;
134    char dummy;
135
136    if (argc != 3 && argc != 6) {
137        ti->error = "requires exactly 3 or 6 arguments";
138        return -EINVAL;
139    }
140
141    dc = kmalloc(sizeof(*dc), GFP_KERNEL);
142    if (!dc) {
143        ti->error = "Cannot allocate context";
144        return -ENOMEM;
145    }
146
147    dc->reads = dc->writes = 0;
148
149    if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) {
150        ti->error = "Invalid device sector";
151        goto bad;
152    }
153    dc->start_read = tmpll;
154
155    if (sscanf(argv[2], "%u%c", &dc->read_delay, &dummy) != 1) {
156        ti->error = "Invalid delay";
157        goto bad;
158    }
159
160    if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
161              &dc->dev_read)) {
162        ti->error = "Device lookup failed";
163        goto bad;
164    }
165
166    dc->dev_write = NULL;
167    if (argc == 3)
168        goto out;
169
170    if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
171        ti->error = "Invalid write device sector";
172        goto bad_dev_read;
173    }
174    dc->start_write = tmpll;
175
176    if (sscanf(argv[5], "%u%c", &dc->write_delay, &dummy) != 1) {
177        ti->error = "Invalid write delay";
178        goto bad_dev_read;
179    }
180
181    if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table),
182              &dc->dev_write)) {
183        ti->error = "Write device lookup failed";
184        goto bad_dev_read;
185    }
186
187out:
188    dc->delayed_pool = mempool_create_slab_pool(128, delayed_cache);
189    if (!dc->delayed_pool) {
190        DMERR("Couldn't create delayed bio pool.");
191        goto bad_dev_write;
192    }
193
194    setup_timer(&dc->delay_timer, handle_delayed_timer, (unsigned long)dc);
195
196    INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
197    INIT_LIST_HEAD(&dc->delayed_bios);
198    mutex_init(&dc->timer_lock);
199    atomic_set(&dc->may_delay, 1);
200
201    ti->num_flush_bios = 1;
202    ti->num_discard_bios = 1;
203    ti->private = dc;
204    return 0;
205
206bad_dev_write:
207    if (dc->dev_write)
208        dm_put_device(ti, dc->dev_write);
209bad_dev_read:
210    dm_put_device(ti, dc->dev_read);
211bad:
212    kfree(dc);
213    return -EINVAL;
214}
215
216static void delay_dtr(struct dm_target *ti)
217{
218    struct delay_c *dc = ti->private;
219
220    flush_workqueue(kdelayd_wq);
221
222    dm_put_device(ti, dc->dev_read);
223
224    if (dc->dev_write)
225        dm_put_device(ti, dc->dev_write);
226
227    mempool_destroy(dc->delayed_pool);
228    kfree(dc);
229}
230
231static int delay_bio(struct delay_c *dc, int delay, struct bio *bio)
232{
233    struct dm_delay_info *delayed;
234    unsigned long expires = 0;
235
236    if (!delay || !atomic_read(&dc->may_delay))
237        return 1;
238
239    delayed = mempool_alloc(dc->delayed_pool, GFP_NOIO);
240
241    delayed->context = dc;
242    delayed->bio = bio;
243    delayed->expires = expires = jiffies + (delay * HZ / 1000);
244
245    mutex_lock(&delayed_bios_lock);
246
247    if (bio_data_dir(bio) == WRITE)
248        dc->writes++;
249    else
250        dc->reads++;
251
252    list_add_tail(&delayed->list, &dc->delayed_bios);
253
254    mutex_unlock(&delayed_bios_lock);
255
256    queue_timeout(dc, expires);
257
258    return 0;
259}
260
261static void delay_presuspend(struct dm_target *ti)
262{
263    struct delay_c *dc = ti->private;
264
265    atomic_set(&dc->may_delay, 0);
266    del_timer_sync(&dc->delay_timer);
267    flush_bios(flush_delayed_bios(dc, 1));
268}
269
270static void delay_resume(struct dm_target *ti)
271{
272    struct delay_c *dc = ti->private;
273
274    atomic_set(&dc->may_delay, 1);
275}
276
277static int delay_map(struct dm_target *ti, struct bio *bio)
278{
279    struct delay_c *dc = ti->private;
280
281    if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
282        bio->bi_bdev = dc->dev_write->bdev;
283        if (bio_sectors(bio))
284            bio->bi_sector = dc->start_write +
285                     dm_target_offset(ti, bio->bi_sector);
286
287        return delay_bio(dc, dc->write_delay, bio);
288    }
289
290    bio->bi_bdev = dc->dev_read->bdev;
291    bio->bi_sector = dc->start_read + dm_target_offset(ti, bio->bi_sector);
292
293    return delay_bio(dc, dc->read_delay, bio);
294}
295
296static void delay_status(struct dm_target *ti, status_type_t type,
297             unsigned status_flags, char *result, unsigned maxlen)
298{
299    struct delay_c *dc = ti->private;
300    int sz = 0;
301
302    switch (type) {
303    case STATUSTYPE_INFO:
304        DMEMIT("%u %u", dc->reads, dc->writes);
305        break;
306
307    case STATUSTYPE_TABLE:
308        DMEMIT("%s %llu %u", dc->dev_read->name,
309               (unsigned long long) dc->start_read,
310               dc->read_delay);
311        if (dc->dev_write)
312            DMEMIT(" %s %llu %u", dc->dev_write->name,
313                   (unsigned long long) dc->start_write,
314                   dc->write_delay);
315        break;
316    }
317}
318
319static int delay_iterate_devices(struct dm_target *ti,
320                 iterate_devices_callout_fn fn, void *data)
321{
322    struct delay_c *dc = ti->private;
323    int ret = 0;
324
325    ret = fn(ti, dc->dev_read, dc->start_read, ti->len, data);
326    if (ret)
327        goto out;
328
329    if (dc->dev_write)
330        ret = fn(ti, dc->dev_write, dc->start_write, ti->len, data);
331
332out:
333    return ret;
334}
335
336static struct target_type delay_target = {
337    .name = "delay",
338    .version = {1, 2, 1},
339    .module = THIS_MODULE,
340    .ctr = delay_ctr,
341    .dtr = delay_dtr,
342    .map = delay_map,
343    .presuspend = delay_presuspend,
344    .resume = delay_resume,
345    .status = delay_status,
346    .iterate_devices = delay_iterate_devices,
347};
348
349static int __init dm_delay_init(void)
350{
351    int r = -ENOMEM;
352
353    kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0);
354    if (!kdelayd_wq) {
355        DMERR("Couldn't start kdelayd");
356        goto bad_queue;
357    }
358
359    delayed_cache = KMEM_CACHE(dm_delay_info, 0);
360    if (!delayed_cache) {
361        DMERR("Couldn't create delayed bio cache.");
362        goto bad_memcache;
363    }
364
365    r = dm_register_target(&delay_target);
366    if (r < 0) {
367        DMERR("register failed %d", r);
368        goto bad_register;
369    }
370
371    return 0;
372
373bad_register:
374    kmem_cache_destroy(delayed_cache);
375bad_memcache:
376    destroy_workqueue(kdelayd_wq);
377bad_queue:
378    return r;
379}
380
381static void __exit dm_delay_exit(void)
382{
383    dm_unregister_target(&delay_target);
384    kmem_cache_destroy(delayed_cache);
385    destroy_workqueue(kdelayd_wq);
386}
387
388/* Module hooks */
389module_init(dm_delay_init);
390module_exit(dm_delay_exit);
391
392MODULE_DESCRIPTION(DM_NAME " delay target");
393MODULE_AUTHOR("Heinz Mauelshagen <mauelshagen@redhat.com>");
394MODULE_LICENSE("GPL");
395

Archive Download this file



interactive