linux/drivers/md/dm-delay.c
<<
>>
Prefs
   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_requests = 1;
 202        ti->num_discard_requests = 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                     union map_info *map_context)
 279{
 280        struct delay_c *dc = ti->private;
 281
 282        if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
 283                bio->bi_bdev = dc->dev_write->bdev;
 284                if (bio_sectors(bio))
 285                        bio->bi_sector = dc->start_write +
 286                                         dm_target_offset(ti, bio->bi_sector);
 287
 288                return delay_bio(dc, dc->write_delay, bio);
 289        }
 290
 291        bio->bi_bdev = dc->dev_read->bdev;
 292        bio->bi_sector = dc->start_read + dm_target_offset(ti, bio->bi_sector);
 293
 294        return delay_bio(dc, dc->read_delay, bio);
 295}
 296
 297static int delay_status(struct dm_target *ti, status_type_t type,
 298                        unsigned status_flags, char *result, unsigned maxlen)
 299{
 300        struct delay_c *dc = ti->private;
 301        int sz = 0;
 302
 303        switch (type) {
 304        case STATUSTYPE_INFO:
 305                DMEMIT("%u %u", dc->reads, dc->writes);
 306                break;
 307
 308        case STATUSTYPE_TABLE:
 309                DMEMIT("%s %llu %u", dc->dev_read->name,
 310                       (unsigned long long) dc->start_read,
 311                       dc->read_delay);
 312                if (dc->dev_write)
 313                        DMEMIT(" %s %llu %u", dc->dev_write->name,
 314                               (unsigned long long) dc->start_write,
 315                               dc->write_delay);
 316                break;
 317        }
 318
 319        return 0;
 320}
 321
 322static int delay_iterate_devices(struct dm_target *ti,
 323                                 iterate_devices_callout_fn fn, void *data)
 324{
 325        struct delay_c *dc = ti->private;
 326        int ret = 0;
 327
 328        ret = fn(ti, dc->dev_read, dc->start_read, ti->len, data);
 329        if (ret)
 330                goto out;
 331
 332        if (dc->dev_write)
 333                ret = fn(ti, dc->dev_write, dc->start_write, ti->len, data);
 334
 335out:
 336        return ret;
 337}
 338
 339static struct target_type delay_target = {
 340        .name        = "delay",
 341        .version     = {1, 1, 0},
 342        .module      = THIS_MODULE,
 343        .ctr         = delay_ctr,
 344        .dtr         = delay_dtr,
 345        .map         = delay_map,
 346        .presuspend  = delay_presuspend,
 347        .resume      = delay_resume,
 348        .status      = delay_status,
 349        .iterate_devices = delay_iterate_devices,
 350};
 351
 352static int __init dm_delay_init(void)
 353{
 354        int r = -ENOMEM;
 355
 356        kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0);
 357        if (!kdelayd_wq) {
 358                DMERR("Couldn't start kdelayd");
 359                goto bad_queue;
 360        }
 361
 362        delayed_cache = KMEM_CACHE(dm_delay_info, 0);
 363        if (!delayed_cache) {
 364                DMERR("Couldn't create delayed bio cache.");
 365                goto bad_memcache;
 366        }
 367
 368        r = dm_register_target(&delay_target);
 369        if (r < 0) {
 370                DMERR("register failed %d", r);
 371                goto bad_register;
 372        }
 373
 374        return 0;
 375
 376bad_register:
 377        kmem_cache_destroy(delayed_cache);
 378bad_memcache:
 379        destroy_workqueue(kdelayd_wq);
 380bad_queue:
 381        return r;
 382}
 383
 384static void __exit dm_delay_exit(void)
 385{
 386        dm_unregister_target(&delay_target);
 387        kmem_cache_destroy(delayed_cache);
 388        destroy_workqueue(kdelayd_wq);
 389}
 390
 391/* Module hooks */
 392module_init(dm_delay_init);
 393module_exit(dm_delay_exit);
 394
 395MODULE_DESCRIPTION(DM_NAME " delay target");
 396MODULE_AUTHOR("Heinz Mauelshagen <mauelshagen@redhat.com>");
 397MODULE_LICENSE("GPL");
 398
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.