Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2001 Sistina Software (UK) Limited |
| 3 | * |
| 4 | * This file is released under the GPL. |
| 5 | */ |
| 6 | |
Mike Snitzer | 4cc9613 | 2016-05-12 16:28:10 -0400 | [diff] [blame] | 7 | #include "dm-core.h" |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 8 | |
| 9 | #include <linux/module.h> |
| 10 | #include <linux/init.h> |
| 11 | #include <linux/kmod.h> |
| 12 | #include <linux/bio.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | |
Alasdair G Kergon | 72d9486 | 2006-06-26 00:27:35 -0700 | [diff] [blame] | 14 | #define DM_MSG_PREFIX "target" |
| 15 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 | static LIST_HEAD(_targets); |
| 17 | static DECLARE_RWSEM(_lock); |
| 18 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 19 | static inline struct target_type *__find_target_type(const char *name) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | { |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 21 | struct target_type *tt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 23 | list_for_each_entry(tt, &_targets, list) |
| 24 | if (!strcmp(name, tt->name)) |
| 25 | return tt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 26 | |
| 27 | return NULL; |
| 28 | } |
| 29 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 30 | static struct target_type *get_target_type(const char *name) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | { |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 32 | struct target_type *tt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | |
| 34 | down_read(&_lock); |
| 35 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 36 | tt = __find_target_type(name); |
| 37 | if (tt && !try_module_get(tt->module)) |
| 38 | tt = NULL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | |
| 40 | up_read(&_lock); |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 41 | return tt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | static void load_module(const char *name) |
| 45 | { |
| 46 | request_module("dm-%s", name); |
| 47 | } |
| 48 | |
| 49 | struct target_type *dm_get_target_type(const char *name) |
| 50 | { |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 51 | struct target_type *tt = get_target_type(name); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 53 | if (!tt) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | load_module(name); |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 55 | tt = get_target_type(name); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | } |
| 57 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 58 | return tt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | } |
| 60 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 61 | void dm_put_target_type(struct target_type *tt) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 62 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | down_read(&_lock); |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 64 | module_put(tt->module); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | up_read(&_lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 66 | } |
| 67 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 | int dm_target_iterate(void (*iter_func)(struct target_type *tt, |
| 69 | void *param), void *param) |
| 70 | { |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 71 | struct target_type *tt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | |
| 73 | down_read(&_lock); |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 74 | list_for_each_entry(tt, &_targets, list) |
| 75 | iter_func(tt, param); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | up_read(&_lock); |
| 77 | |
| 78 | return 0; |
| 79 | } |
| 80 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 81 | int dm_register_target(struct target_type *tt) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | { |
| 83 | int rv = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | |
| 85 | down_write(&_lock); |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 86 | if (__find_target_type(tt->name)) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | rv = -EEXIST; |
| 88 | else |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 89 | list_add(&tt->list, &_targets); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | |
| 91 | up_write(&_lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 | return rv; |
| 93 | } |
| 94 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 95 | void dm_unregister_target(struct target_type *tt) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | down_write(&_lock); |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 98 | if (!__find_target_type(tt->name)) { |
| 99 | DMCRIT("Unregistering unrecognised target: %s", tt->name); |
Mikulas Patocka | 10d3bd0 | 2009-01-06 03:04:58 +0000 | [diff] [blame] | 100 | BUG(); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 | } |
| 102 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 103 | list_del(&tt->list); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 104 | |
| 105 | up_write(&_lock); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | /* |
| 109 | * io-err: always fails an io, useful for bringing |
| 110 | * up LVs that have holes in them. |
| 111 | */ |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 112 | static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 113 | { |
Mike Snitzer | 38e1b25 | 2010-08-12 04:14:14 +0100 | [diff] [blame] | 114 | /* |
| 115 | * Return error for discards instead of -EOPNOTSUPP |
| 116 | */ |
Alasdair G Kergon | 55a62ee | 2013-03-01 22:45:47 +0000 | [diff] [blame] | 117 | tt->num_discard_bios = 1; |
Mike Snitzer | 38e1b25 | 2010-08-12 04:14:14 +0100 | [diff] [blame] | 118 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 | return 0; |
| 120 | } |
| 121 | |
Cheng Renquan | 45194e4 | 2009-04-02 19:55:28 +0100 | [diff] [blame] | 122 | static void io_err_dtr(struct dm_target *tt) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | { |
| 124 | /* empty */ |
| 125 | } |
| 126 | |
Mikulas Patocka | 7de3ee5 | 2012-12-21 20:23:41 +0000 | [diff] [blame] | 127 | static int io_err_map(struct dm_target *tt, struct bio *bio) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | { |
Christoph Hellwig | 846785e | 2017-06-03 09:38:02 +0200 | [diff] [blame] | 129 | return DM_MAPIO_KILL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 | } |
| 131 | |
Mike Snitzer | e5863d9 | 2014-12-17 21:08:12 -0500 | [diff] [blame] | 132 | static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq, |
| 133 | union map_info *map_context, |
| 134 | struct request **clone) |
| 135 | { |
Christoph Hellwig | 412445a | 2017-04-26 09:40:39 +0200 | [diff] [blame] | 136 | return DM_MAPIO_KILL; |
Mike Snitzer | e5863d9 | 2014-12-17 21:08:12 -0500 | [diff] [blame] | 137 | } |
| 138 | |
| 139 | static void io_err_release_clone_rq(struct request *clone) |
| 140 | { |
| 141 | } |
| 142 | |
Dan Williams | 817bf40 | 2017-04-12 13:37:44 -0700 | [diff] [blame] | 143 | static long io_err_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
| 144 | long nr_pages, void **kaddr, pfn_t *pfn) |
Mike Snitzer | f8df1fd | 2016-06-24 17:09:35 -0400 | [diff] [blame] | 145 | { |
| 146 | return -EIO; |
| 147 | } |
| 148 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 149 | static struct target_type error_target = { |
| 150 | .name = "error", |
Mike Snitzer | f8df1fd | 2016-06-24 17:09:35 -0400 | [diff] [blame] | 151 | .version = {1, 5, 0}, |
Mike Snitzer | f083b09 | 2016-02-06 18:38:46 -0500 | [diff] [blame] | 152 | .features = DM_TARGET_WILDCARD, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 153 | .ctr = io_err_ctr, |
| 154 | .dtr = io_err_dtr, |
| 155 | .map = io_err_map, |
Mike Snitzer | e5863d9 | 2014-12-17 21:08:12 -0500 | [diff] [blame] | 156 | .clone_and_map_rq = io_err_clone_and_map_rq, |
| 157 | .release_clone_rq = io_err_release_clone_rq, |
Dan Williams | 817bf40 | 2017-04-12 13:37:44 -0700 | [diff] [blame] | 158 | .direct_access = io_err_dax_direct_access, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 159 | }; |
| 160 | |
| 161 | int __init dm_target_init(void) |
| 162 | { |
| 163 | return dm_register_target(&error_target); |
| 164 | } |
| 165 | |
| 166 | void dm_target_exit(void) |
| 167 | { |
Mikulas Patocka | 10d3bd0 | 2009-01-06 03:04:58 +0000 | [diff] [blame] | 168 | dm_unregister_target(&error_target); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | EXPORT_SYMBOL(dm_register_target); |
| 172 | EXPORT_SYMBOL(dm_unregister_target); |