diff options
Diffstat (limited to 'drivers/md/dm-stripe.c')
-rw-r--r-- | drivers/md/dm-stripe.c | 105 |
1 files changed, 103 insertions, 2 deletions
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 969944a8aba2..4de90ab3968b 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -14,10 +14,13 @@ | |||
14 | #include <linux/log2.h> | 14 | #include <linux/log2.h> |
15 | 15 | ||
16 | #define DM_MSG_PREFIX "striped" | 16 | #define DM_MSG_PREFIX "striped" |
17 | #define DM_IO_ERROR_THRESHOLD 15 | ||
17 | 18 | ||
18 | struct stripe { | 19 | struct stripe { |
19 | struct dm_dev *dev; | 20 | struct dm_dev *dev; |
20 | sector_t physical_start; | 21 | sector_t physical_start; |
22 | |||
23 | atomic_t error_count; | ||
21 | }; | 24 | }; |
22 | 25 | ||
23 | struct stripe_c { | 26 | struct stripe_c { |
@@ -30,9 +33,29 @@ struct stripe_c { | |||
30 | uint32_t chunk_shift; | 33 | uint32_t chunk_shift; |
31 | sector_t chunk_mask; | 34 | sector_t chunk_mask; |
32 | 35 | ||
36 | /* Needed for handling events */ | ||
37 | struct dm_target *ti; | ||
38 | |||
39 | /* Work struct used for triggering events*/ | ||
40 | struct work_struct kstriped_ws; | ||
41 | |||
33 | struct stripe stripe[0]; | 42 | struct stripe stripe[0]; |
34 | }; | 43 | }; |
35 | 44 | ||
45 | static struct workqueue_struct *kstriped; | ||
46 | |||
47 | /* | ||
48 | * An event is triggered whenever a drive | ||
49 | * drops out of a stripe volume. | ||
50 | */ | ||
51 | static void trigger_event(struct work_struct *work) | ||
52 | { | ||
53 | struct stripe_c *sc = container_of(work, struct stripe_c, kstriped_ws); | ||
54 | |||
55 | dm_table_event(sc->ti->table); | ||
56 | |||
57 | } | ||
58 | |||
36 | static inline struct stripe_c *alloc_context(unsigned int stripes) | 59 | static inline struct stripe_c *alloc_context(unsigned int stripes) |
37 | { | 60 | { |
38 | size_t len; | 61 | size_t len; |
@@ -63,6 +86,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc, | |||
63 | return -ENXIO; | 86 | return -ENXIO; |
64 | 87 | ||
65 | sc->stripe[stripe].physical_start = start; | 88 | sc->stripe[stripe].physical_start = start; |
89 | |||
66 | return 0; | 90 | return 0; |
67 | } | 91 | } |
68 | 92 | ||
@@ -135,6 +159,11 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
135 | return -ENOMEM; | 159 | return -ENOMEM; |
136 | } | 160 | } |
137 | 161 | ||
162 | INIT_WORK(&sc->kstriped_ws, trigger_event); | ||
163 | |||
164 | /* Set pointer to dm target; used in trigger_event */ | ||
165 | sc->ti = ti; | ||
166 | |||
138 | sc->stripes = stripes; | 167 | sc->stripes = stripes; |
139 | sc->stripe_width = width; | 168 | sc->stripe_width = width; |
140 | ti->split_io = chunk_size; | 169 | ti->split_io = chunk_size; |
@@ -158,9 +187,11 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
158 | kfree(sc); | 187 | kfree(sc); |
159 | return r; | 188 | return r; |
160 | } | 189 | } |
190 | atomic_set(&(sc->stripe[i].error_count), 0); | ||
161 | } | 191 | } |
162 | 192 | ||
163 | ti->private = sc; | 193 | ti->private = sc; |
194 | |||
164 | return 0; | 195 | return 0; |
165 | } | 196 | } |
166 | 197 | ||
@@ -172,6 +203,7 @@ static void stripe_dtr(struct dm_target *ti) | |||
172 | for (i = 0; i < sc->stripes; i++) | 203 | for (i = 0; i < sc->stripes; i++) |
173 | dm_put_device(ti, sc->stripe[i].dev); | 204 | dm_put_device(ti, sc->stripe[i].dev); |
174 | 205 | ||
206 | flush_workqueue(kstriped); | ||
175 | kfree(sc); | 207 | kfree(sc); |
176 | } | 208 | } |
177 | 209 | ||
@@ -190,16 +222,37 @@ static int stripe_map(struct dm_target *ti, struct bio *bio, | |||
190 | return DM_MAPIO_REMAPPED; | 222 | return DM_MAPIO_REMAPPED; |
191 | } | 223 | } |
192 | 224 | ||
225 | /* | ||
226 | * Stripe status: | ||
227 | * | ||
228 | * INFO | ||
229 | * #stripes [stripe_name <stripe_name>] [group word count] | ||
230 | * [error count 'A|D' <error count 'A|D'>] | ||
231 | * | ||
232 | * TABLE | ||
233 | * #stripes [stripe chunk size] | ||
234 | * [stripe_name physical_start <stripe_name physical_start>] | ||
235 | * | ||
236 | */ | ||
237 | |||
193 | static int stripe_status(struct dm_target *ti, | 238 | static int stripe_status(struct dm_target *ti, |
194 | status_type_t type, char *result, unsigned int maxlen) | 239 | status_type_t type, char *result, unsigned int maxlen) |
195 | { | 240 | { |
196 | struct stripe_c *sc = (struct stripe_c *) ti->private; | 241 | struct stripe_c *sc = (struct stripe_c *) ti->private; |
242 | char buffer[sc->stripes + 1]; | ||
197 | unsigned int sz = 0; | 243 | unsigned int sz = 0; |
198 | unsigned int i; | 244 | unsigned int i; |
199 | 245 | ||
200 | switch (type) { | 246 | switch (type) { |
201 | case STATUSTYPE_INFO: | 247 | case STATUSTYPE_INFO: |
202 | result[0] = '\0'; | 248 | DMEMIT("%d ", sc->stripes); |
249 | for (i = 0; i < sc->stripes; i++) { | ||
250 | DMEMIT("%s ", sc->stripe[i].dev->name); | ||
251 | buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ? | ||
252 | 'D' : 'A'; | ||
253 | } | ||
254 | buffer[i] = '\0'; | ||
255 | DMEMIT("1 %s", buffer); | ||
203 | break; | 256 | break; |
204 | 257 | ||
205 | case STATUSTYPE_TABLE: | 258 | case STATUSTYPE_TABLE: |
@@ -213,13 +266,52 @@ static int stripe_status(struct dm_target *ti, | |||
213 | return 0; | 266 | return 0; |
214 | } | 267 | } |
215 | 268 | ||
269 | static int stripe_end_io(struct dm_target *ti, struct bio *bio, | ||
270 | int error, union map_info *map_context) | ||
271 | { | ||
272 | unsigned i; | ||
273 | char major_minor[16]; | ||
274 | struct stripe_c *sc = ti->private; | ||
275 | |||
276 | if (!error) | ||
277 | return 0; /* I/O complete */ | ||
278 | |||
279 | if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) | ||
280 | return error; | ||
281 | |||
282 | if (error == -EOPNOTSUPP) | ||
283 | return error; | ||
284 | |||
285 | memset(major_minor, 0, sizeof(major_minor)); | ||
286 | sprintf(major_minor, "%d:%d", | ||
287 | bio->bi_bdev->bd_disk->major, | ||
288 | bio->bi_bdev->bd_disk->first_minor); | ||
289 | |||
290 | /* | ||
291 | * Test to see which stripe drive triggered the event | ||
292 | * and increment error count for all stripes on that device. | ||
293 | * If the error count for a given device exceeds the threshold | ||
294 | * value we will no longer trigger any further events. | ||
295 | */ | ||
296 | for (i = 0; i < sc->stripes; i++) | ||
297 | if (!strcmp(sc->stripe[i].dev->name, major_minor)) { | ||
298 | atomic_inc(&(sc->stripe[i].error_count)); | ||
299 | if (atomic_read(&(sc->stripe[i].error_count)) < | ||
300 | DM_IO_ERROR_THRESHOLD) | ||
301 | queue_work(kstriped, &sc->kstriped_ws); | ||
302 | } | ||
303 | |||
304 | return error; | ||
305 | } | ||
306 | |||
216 | static struct target_type stripe_target = { | 307 | static struct target_type stripe_target = { |
217 | .name = "striped", | 308 | .name = "striped", |
218 | .version= {1, 0, 2}, | 309 | .version = {1, 1, 0}, |
219 | .module = THIS_MODULE, | 310 | .module = THIS_MODULE, |
220 | .ctr = stripe_ctr, | 311 | .ctr = stripe_ctr, |
221 | .dtr = stripe_dtr, | 312 | .dtr = stripe_dtr, |
222 | .map = stripe_map, | 313 | .map = stripe_map, |
314 | .end_io = stripe_end_io, | ||
223 | .status = stripe_status, | 315 | .status = stripe_status, |
224 | }; | 316 | }; |
225 | 317 | ||
@@ -231,6 +323,13 @@ int __init dm_stripe_init(void) | |||
231 | if (r < 0) | 323 | if (r < 0) |
232 | DMWARN("target registration failed"); | 324 | DMWARN("target registration failed"); |
233 | 325 | ||
326 | kstriped = create_singlethread_workqueue("kstriped"); | ||
327 | if (!kstriped) { | ||
328 | DMERR("failed to create workqueue kstriped"); | ||
329 | dm_unregister_target(&stripe_target); | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | |||
234 | return r; | 333 | return r; |
235 | } | 334 | } |
236 | 335 | ||
@@ -239,5 +338,7 @@ void dm_stripe_exit(void) | |||
239 | if (dm_unregister_target(&stripe_target)) | 338 | if (dm_unregister_target(&stripe_target)) |
240 | DMWARN("target unregistration failed"); | 339 | DMWARN("target unregistration failed"); |
241 | 340 | ||
341 | destroy_workqueue(kstriped); | ||
342 | |||
242 | return; | 343 | return; |
243 | } | 344 | } |