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