18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 Red Hat GmbH 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * A target that delays reads and/or writes and can send 58c2ecf20Sopenharmony_ci * them to different devices. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file is released under the GPL. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 138c2ecf20Sopenharmony_ci#include <linux/bio.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/device-mapper.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "delay" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct delay_class { 218c2ecf20Sopenharmony_ci struct dm_dev *dev; 228c2ecf20Sopenharmony_ci sector_t start; 238c2ecf20Sopenharmony_ci unsigned delay; 248c2ecf20Sopenharmony_ci unsigned ops; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct delay_c { 288c2ecf20Sopenharmony_ci struct timer_list delay_timer; 298c2ecf20Sopenharmony_ci struct mutex timer_lock; 308c2ecf20Sopenharmony_ci struct workqueue_struct *kdelayd_wq; 318c2ecf20Sopenharmony_ci struct work_struct flush_expired_bios; 328c2ecf20Sopenharmony_ci struct list_head delayed_bios; 338c2ecf20Sopenharmony_ci bool may_delay; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci struct delay_class read; 368c2ecf20Sopenharmony_ci struct delay_class write; 378c2ecf20Sopenharmony_ci struct delay_class flush; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci int argc; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct dm_delay_info { 438c2ecf20Sopenharmony_ci struct delay_c *context; 448c2ecf20Sopenharmony_ci struct delay_class *class; 458c2ecf20Sopenharmony_ci struct list_head list; 468c2ecf20Sopenharmony_ci unsigned long expires; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(delayed_bios_lock); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void handle_delayed_timer(struct timer_list *t) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct delay_c *dc = from_timer(dc, t, delay_timer); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci queue_work(dc->kdelayd_wq, &dc->flush_expired_bios); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void queue_timeout(struct delay_c *dc, unsigned long expires) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci mutex_lock(&dc->timer_lock); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!timer_pending(&dc->delay_timer) || expires < dc->delay_timer.expires) 638c2ecf20Sopenharmony_ci mod_timer(&dc->delay_timer, expires); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci mutex_unlock(&dc->timer_lock); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void flush_bios(struct bio *bio) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct bio *n; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci while (bio) { 738c2ecf20Sopenharmony_ci n = bio->bi_next; 748c2ecf20Sopenharmony_ci bio->bi_next = NULL; 758c2ecf20Sopenharmony_ci submit_bio_noacct(bio); 768c2ecf20Sopenharmony_ci bio = n; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct dm_delay_info *delayed, *next; 838c2ecf20Sopenharmony_ci unsigned long next_expires = 0; 848c2ecf20Sopenharmony_ci unsigned long start_timer = 0; 858c2ecf20Sopenharmony_ci struct bio_list flush_bios = { }; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci mutex_lock(&delayed_bios_lock); 888c2ecf20Sopenharmony_ci list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) { 898c2ecf20Sopenharmony_ci if (flush_all || time_after_eq(jiffies, delayed->expires)) { 908c2ecf20Sopenharmony_ci struct bio *bio = dm_bio_from_per_bio_data(delayed, 918c2ecf20Sopenharmony_ci sizeof(struct dm_delay_info)); 928c2ecf20Sopenharmony_ci list_del(&delayed->list); 938c2ecf20Sopenharmony_ci bio_list_add(&flush_bios, bio); 948c2ecf20Sopenharmony_ci delayed->class->ops--; 958c2ecf20Sopenharmony_ci continue; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!start_timer) { 998c2ecf20Sopenharmony_ci start_timer = 1; 1008c2ecf20Sopenharmony_ci next_expires = delayed->expires; 1018c2ecf20Sopenharmony_ci } else 1028c2ecf20Sopenharmony_ci next_expires = min(next_expires, delayed->expires); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci mutex_unlock(&delayed_bios_lock); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (start_timer) 1078c2ecf20Sopenharmony_ci queue_timeout(dc, next_expires); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return bio_list_get(&flush_bios); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void flush_expired_bios(struct work_struct *work) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct delay_c *dc; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci dc = container_of(work, struct delay_c, flush_expired_bios); 1178c2ecf20Sopenharmony_ci flush_bios(flush_delayed_bios(dc, 0)); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void delay_dtr(struct dm_target *ti) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct delay_c *dc = ti->private; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (dc->kdelayd_wq) 1258c2ecf20Sopenharmony_ci destroy_workqueue(dc->kdelayd_wq); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (dc->read.dev) 1288c2ecf20Sopenharmony_ci dm_put_device(ti, dc->read.dev); 1298c2ecf20Sopenharmony_ci if (dc->write.dev) 1308c2ecf20Sopenharmony_ci dm_put_device(ti, dc->write.dev); 1318c2ecf20Sopenharmony_ci if (dc->flush.dev) 1328c2ecf20Sopenharmony_ci dm_put_device(ti, dc->flush.dev); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci mutex_destroy(&dc->timer_lock); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci kfree(dc); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int delay_class_ctr(struct dm_target *ti, struct delay_class *c, char **argv) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int ret; 1428c2ecf20Sopenharmony_ci unsigned long long tmpll; 1438c2ecf20Sopenharmony_ci char dummy; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { 1468c2ecf20Sopenharmony_ci ti->error = "Invalid device sector"; 1478c2ecf20Sopenharmony_ci return -EINVAL; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci c->start = tmpll; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (sscanf(argv[2], "%u%c", &c->delay, &dummy) != 1) { 1528c2ecf20Sopenharmony_ci ti->error = "Invalid delay"; 1538c2ecf20Sopenharmony_ci return -EINVAL; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &c->dev); 1578c2ecf20Sopenharmony_ci if (ret) { 1588c2ecf20Sopenharmony_ci ti->error = "Device lookup failed"; 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * Mapping parameters: 1678c2ecf20Sopenharmony_ci * <device> <offset> <delay> [<write_device> <write_offset> <write_delay>] 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * With separate write parameters, the first set is only used for reads. 1708c2ecf20Sopenharmony_ci * Offsets are specified in sectors. 1718c2ecf20Sopenharmony_ci * Delays are specified in milliseconds. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_cistatic int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct delay_c *dc; 1768c2ecf20Sopenharmony_ci int ret; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (argc != 3 && argc != 6 && argc != 9) { 1798c2ecf20Sopenharmony_ci ti->error = "Requires exactly 3, 6 or 9 arguments"; 1808c2ecf20Sopenharmony_ci return -EINVAL; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci dc = kzalloc(sizeof(*dc), GFP_KERNEL); 1848c2ecf20Sopenharmony_ci if (!dc) { 1858c2ecf20Sopenharmony_ci ti->error = "Cannot allocate context"; 1868c2ecf20Sopenharmony_ci return -ENOMEM; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ti->private = dc; 1908c2ecf20Sopenharmony_ci timer_setup(&dc->delay_timer, handle_delayed_timer, 0); 1918c2ecf20Sopenharmony_ci INIT_WORK(&dc->flush_expired_bios, flush_expired_bios); 1928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dc->delayed_bios); 1938c2ecf20Sopenharmony_ci mutex_init(&dc->timer_lock); 1948c2ecf20Sopenharmony_ci dc->may_delay = true; 1958c2ecf20Sopenharmony_ci dc->argc = argc; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ret = delay_class_ctr(ti, &dc->read, argv); 1988c2ecf20Sopenharmony_ci if (ret) 1998c2ecf20Sopenharmony_ci goto bad; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (argc == 3) { 2028c2ecf20Sopenharmony_ci ret = delay_class_ctr(ti, &dc->write, argv); 2038c2ecf20Sopenharmony_ci if (ret) 2048c2ecf20Sopenharmony_ci goto bad; 2058c2ecf20Sopenharmony_ci ret = delay_class_ctr(ti, &dc->flush, argv); 2068c2ecf20Sopenharmony_ci if (ret) 2078c2ecf20Sopenharmony_ci goto bad; 2088c2ecf20Sopenharmony_ci goto out; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci ret = delay_class_ctr(ti, &dc->write, argv + 3); 2128c2ecf20Sopenharmony_ci if (ret) 2138c2ecf20Sopenharmony_ci goto bad; 2148c2ecf20Sopenharmony_ci if (argc == 6) { 2158c2ecf20Sopenharmony_ci ret = delay_class_ctr(ti, &dc->flush, argv + 3); 2168c2ecf20Sopenharmony_ci if (ret) 2178c2ecf20Sopenharmony_ci goto bad; 2188c2ecf20Sopenharmony_ci goto out; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ret = delay_class_ctr(ti, &dc->flush, argv + 6); 2228c2ecf20Sopenharmony_ci if (ret) 2238c2ecf20Sopenharmony_ci goto bad; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciout: 2268c2ecf20Sopenharmony_ci dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0); 2278c2ecf20Sopenharmony_ci if (!dc->kdelayd_wq) { 2288c2ecf20Sopenharmony_ci ret = -EINVAL; 2298c2ecf20Sopenharmony_ci DMERR("Couldn't start kdelayd"); 2308c2ecf20Sopenharmony_ci goto bad; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ti->num_flush_bios = 1; 2348c2ecf20Sopenharmony_ci ti->num_discard_bios = 1; 2358c2ecf20Sopenharmony_ci ti->per_io_data_size = sizeof(struct dm_delay_info); 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cibad: 2398c2ecf20Sopenharmony_ci delay_dtr(ti); 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int delay_bio(struct delay_c *dc, struct delay_class *c, struct bio *bio) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct dm_delay_info *delayed; 2468c2ecf20Sopenharmony_ci unsigned long expires = 0; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (!c->delay) 2498c2ecf20Sopenharmony_ci return DM_MAPIO_REMAPPED; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci delayed = dm_per_bio_data(bio, sizeof(struct dm_delay_info)); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci delayed->context = dc; 2548c2ecf20Sopenharmony_ci delayed->expires = expires = jiffies + msecs_to_jiffies(c->delay); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci mutex_lock(&delayed_bios_lock); 2578c2ecf20Sopenharmony_ci if (unlikely(!dc->may_delay)) { 2588c2ecf20Sopenharmony_ci mutex_unlock(&delayed_bios_lock); 2598c2ecf20Sopenharmony_ci return DM_MAPIO_REMAPPED; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci c->ops++; 2628c2ecf20Sopenharmony_ci list_add_tail(&delayed->list, &dc->delayed_bios); 2638c2ecf20Sopenharmony_ci mutex_unlock(&delayed_bios_lock); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci queue_timeout(dc, expires); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return DM_MAPIO_SUBMITTED; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void delay_presuspend(struct dm_target *ti) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct delay_c *dc = ti->private; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci mutex_lock(&delayed_bios_lock); 2758c2ecf20Sopenharmony_ci dc->may_delay = false; 2768c2ecf20Sopenharmony_ci mutex_unlock(&delayed_bios_lock); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci del_timer_sync(&dc->delay_timer); 2798c2ecf20Sopenharmony_ci flush_bios(flush_delayed_bios(dc, 1)); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void delay_resume(struct dm_target *ti) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct delay_c *dc = ti->private; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci dc->may_delay = true; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int delay_map(struct dm_target *ti, struct bio *bio) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct delay_c *dc = ti->private; 2928c2ecf20Sopenharmony_ci struct delay_class *c; 2938c2ecf20Sopenharmony_ci struct dm_delay_info *delayed = dm_per_bio_data(bio, sizeof(struct dm_delay_info)); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (bio_data_dir(bio) == WRITE) { 2968c2ecf20Sopenharmony_ci if (unlikely(bio->bi_opf & REQ_PREFLUSH)) 2978c2ecf20Sopenharmony_ci c = &dc->flush; 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci c = &dc->write; 3008c2ecf20Sopenharmony_ci } else { 3018c2ecf20Sopenharmony_ci c = &dc->read; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci delayed->class = c; 3048c2ecf20Sopenharmony_ci bio_set_dev(bio, c->dev->bdev); 3058c2ecf20Sopenharmony_ci if (bio_sectors(bio)) 3068c2ecf20Sopenharmony_ci bio->bi_iter.bi_sector = c->start + dm_target_offset(ti, bio->bi_iter.bi_sector); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return delay_bio(dc, c, bio); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci#define DMEMIT_DELAY_CLASS(c) \ 3128c2ecf20Sopenharmony_ci DMEMIT("%s %llu %u", (c)->dev->name, (unsigned long long)(c)->start, (c)->delay) 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic void delay_status(struct dm_target *ti, status_type_t type, 3158c2ecf20Sopenharmony_ci unsigned status_flags, char *result, unsigned maxlen) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct delay_c *dc = ti->private; 3188c2ecf20Sopenharmony_ci int sz = 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci switch (type) { 3218c2ecf20Sopenharmony_ci case STATUSTYPE_INFO: 3228c2ecf20Sopenharmony_ci DMEMIT("%u %u %u", dc->read.ops, dc->write.ops, dc->flush.ops); 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci case STATUSTYPE_TABLE: 3268c2ecf20Sopenharmony_ci DMEMIT_DELAY_CLASS(&dc->read); 3278c2ecf20Sopenharmony_ci if (dc->argc >= 6) { 3288c2ecf20Sopenharmony_ci DMEMIT(" "); 3298c2ecf20Sopenharmony_ci DMEMIT_DELAY_CLASS(&dc->write); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci if (dc->argc >= 9) { 3328c2ecf20Sopenharmony_ci DMEMIT(" "); 3338c2ecf20Sopenharmony_ci DMEMIT_DELAY_CLASS(&dc->flush); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int delay_iterate_devices(struct dm_target *ti, 3408c2ecf20Sopenharmony_ci iterate_devices_callout_fn fn, void *data) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct delay_c *dc = ti->private; 3438c2ecf20Sopenharmony_ci int ret = 0; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci ret = fn(ti, dc->read.dev, dc->read.start, ti->len, data); 3468c2ecf20Sopenharmony_ci if (ret) 3478c2ecf20Sopenharmony_ci goto out; 3488c2ecf20Sopenharmony_ci ret = fn(ti, dc->write.dev, dc->write.start, ti->len, data); 3498c2ecf20Sopenharmony_ci if (ret) 3508c2ecf20Sopenharmony_ci goto out; 3518c2ecf20Sopenharmony_ci ret = fn(ti, dc->flush.dev, dc->flush.start, ti->len, data); 3528c2ecf20Sopenharmony_ci if (ret) 3538c2ecf20Sopenharmony_ci goto out; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciout: 3568c2ecf20Sopenharmony_ci return ret; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic struct target_type delay_target = { 3608c2ecf20Sopenharmony_ci .name = "delay", 3618c2ecf20Sopenharmony_ci .version = {1, 2, 1}, 3628c2ecf20Sopenharmony_ci .features = DM_TARGET_PASSES_INTEGRITY, 3638c2ecf20Sopenharmony_ci .module = THIS_MODULE, 3648c2ecf20Sopenharmony_ci .ctr = delay_ctr, 3658c2ecf20Sopenharmony_ci .dtr = delay_dtr, 3668c2ecf20Sopenharmony_ci .map = delay_map, 3678c2ecf20Sopenharmony_ci .presuspend = delay_presuspend, 3688c2ecf20Sopenharmony_ci .resume = delay_resume, 3698c2ecf20Sopenharmony_ci .status = delay_status, 3708c2ecf20Sopenharmony_ci .iterate_devices = delay_iterate_devices, 3718c2ecf20Sopenharmony_ci}; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int __init dm_delay_init(void) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci int r; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci r = dm_register_target(&delay_target); 3788c2ecf20Sopenharmony_ci if (r < 0) { 3798c2ecf20Sopenharmony_ci DMERR("register failed %d", r); 3808c2ecf20Sopenharmony_ci goto bad_register; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cibad_register: 3868c2ecf20Sopenharmony_ci return r; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic void __exit dm_delay_exit(void) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci dm_unregister_target(&delay_target); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/* Module hooks */ 3958c2ecf20Sopenharmony_cimodule_init(dm_delay_init); 3968c2ecf20Sopenharmony_cimodule_exit(dm_delay_exit); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DM_NAME " delay target"); 3998c2ecf20Sopenharmony_ciMODULE_AUTHOR("Heinz Mauelshagen <mauelshagen@redhat.com>"); 4008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 401