Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (C) 2001 Sistina Software (UK) Limited | |
3 | * | |
4 | * This file is released under the GPL. | |
5 | */ | |
6 | ||
7 | #include "dm.h" | |
8 | ||
9 | #include <linux/module.h> | |
10 | #include <linux/init.h> | |
11 | #include <linux/kmod.h> | |
12 | #include <linux/bio.h> | |
13 | #include <linux/slab.h> | |
14 | ||
15 | struct tt_internal { | |
16 | struct target_type tt; | |
17 | ||
18 | struct list_head list; | |
19 | long use; | |
20 | }; | |
21 | ||
22 | static LIST_HEAD(_targets); | |
23 | static DECLARE_RWSEM(_lock); | |
24 | ||
25 | #define DM_MOD_NAME_SIZE 32 | |
26 | ||
27 | static inline struct tt_internal *__find_target_type(const char *name) | |
28 | { | |
29 | struct tt_internal *ti; | |
30 | ||
31 | list_for_each_entry (ti, &_targets, list) | |
32 | if (!strcmp(name, ti->tt.name)) | |
33 | return ti; | |
34 | ||
35 | return NULL; | |
36 | } | |
37 | ||
38 | static struct tt_internal *get_target_type(const char *name) | |
39 | { | |
40 | struct tt_internal *ti; | |
41 | ||
42 | down_read(&_lock); | |
43 | ||
44 | ti = __find_target_type(name); | |
45 | if (ti) { | |
46 | if ((ti->use == 0) && !try_module_get(ti->tt.module)) | |
47 | ti = NULL; | |
48 | else | |
49 | ti->use++; | |
50 | } | |
51 | ||
52 | up_read(&_lock); | |
53 | return ti; | |
54 | } | |
55 | ||
56 | static void load_module(const char *name) | |
57 | { | |
58 | request_module("dm-%s", name); | |
59 | } | |
60 | ||
61 | struct target_type *dm_get_target_type(const char *name) | |
62 | { | |
63 | struct tt_internal *ti = get_target_type(name); | |
64 | ||
65 | if (!ti) { | |
66 | load_module(name); | |
67 | ti = get_target_type(name); | |
68 | } | |
69 | ||
70 | return ti ? &ti->tt : NULL; | |
71 | } | |
72 | ||
73 | void dm_put_target_type(struct target_type *t) | |
74 | { | |
75 | struct tt_internal *ti = (struct tt_internal *) t; | |
76 | ||
77 | down_read(&_lock); | |
78 | if (--ti->use == 0) | |
79 | module_put(ti->tt.module); | |
80 | ||
81 | if (ti->use < 0) | |
82 | BUG(); | |
83 | up_read(&_lock); | |
84 | ||
85 | return; | |
86 | } | |
87 | ||
88 | static struct tt_internal *alloc_target(struct target_type *t) | |
89 | { | |
90 | struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL); | |
91 | ||
92 | if (ti) { | |
93 | memset(ti, 0, sizeof(*ti)); | |
94 | ti->tt = *t; | |
95 | } | |
96 | ||
97 | return ti; | |
98 | } | |
99 | ||
100 | ||
101 | int dm_target_iterate(void (*iter_func)(struct target_type *tt, | |
102 | void *param), void *param) | |
103 | { | |
104 | struct tt_internal *ti; | |
105 | ||
106 | down_read(&_lock); | |
107 | list_for_each_entry (ti, &_targets, list) | |
108 | iter_func(&ti->tt, param); | |
109 | up_read(&_lock); | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | int dm_register_target(struct target_type *t) | |
115 | { | |
116 | int rv = 0; | |
117 | struct tt_internal *ti = alloc_target(t); | |
118 | ||
119 | if (!ti) | |
120 | return -ENOMEM; | |
121 | ||
122 | down_write(&_lock); | |
123 | if (__find_target_type(t->name)) | |
124 | rv = -EEXIST; | |
125 | else | |
126 | list_add(&ti->list, &_targets); | |
127 | ||
128 | up_write(&_lock); | |
129 | if (rv) | |
130 | kfree(ti); | |
131 | return rv; | |
132 | } | |
133 | ||
134 | int dm_unregister_target(struct target_type *t) | |
135 | { | |
136 | struct tt_internal *ti; | |
137 | ||
138 | down_write(&_lock); | |
139 | if (!(ti = __find_target_type(t->name))) { | |
140 | up_write(&_lock); | |
141 | return -EINVAL; | |
142 | } | |
143 | ||
144 | if (ti->use) { | |
145 | up_write(&_lock); | |
146 | return -ETXTBSY; | |
147 | } | |
148 | ||
149 | list_del(&ti->list); | |
150 | kfree(ti); | |
151 | ||
152 | up_write(&_lock); | |
153 | return 0; | |
154 | } | |
155 | ||
156 | /* | |
157 | * io-err: always fails an io, useful for bringing | |
158 | * up LVs that have holes in them. | |
159 | */ | |
160 | static int io_err_ctr(struct dm_target *ti, unsigned int argc, char **args) | |
161 | { | |
162 | return 0; | |
163 | } | |
164 | ||
165 | static void io_err_dtr(struct dm_target *ti) | |
166 | { | |
167 | /* empty */ | |
168 | } | |
169 | ||
170 | static int io_err_map(struct dm_target *ti, struct bio *bio, | |
171 | union map_info *map_context) | |
172 | { | |
173 | return -EIO; | |
174 | } | |
175 | ||
176 | static struct target_type error_target = { | |
177 | .name = "error", | |
178 | .version = {1, 0, 1}, | |
179 | .ctr = io_err_ctr, | |
180 | .dtr = io_err_dtr, | |
181 | .map = io_err_map, | |
182 | }; | |
183 | ||
184 | int __init dm_target_init(void) | |
185 | { | |
186 | return dm_register_target(&error_target); | |
187 | } | |
188 | ||
189 | void dm_target_exit(void) | |
190 | { | |
191 | if (dm_unregister_target(&error_target)) | |
192 | DMWARN("error target unregistration failed"); | |
193 | } | |
194 | ||
195 | EXPORT_SYMBOL(dm_register_target); | |
196 | EXPORT_SYMBOL(dm_unregister_target); |