aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-stripe.c82
1 files changed, 81 insertions, 1 deletions
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 969944a8aba2..7c5e2a0c3f2d 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
18struct stripe { 19struct 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
23struct stripe_c { 26struct 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
45static struct workqueue_struct *kstriped;
46
47/*
48 * An event is triggered whenever a drive
49 * drops out of a stripe volume.
50 */
51static 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
36static inline struct stripe_c *alloc_context(unsigned int stripes) 59static 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
@@ -213,13 +245,52 @@ static int stripe_status(struct dm_target *ti,
213 return 0; 245 return 0;
214} 246}
215 247
248static int stripe_end_io(struct dm_target *ti, struct bio *bio,
249 int error, union map_info *map_context)
250{
251 unsigned i;
252 char major_minor[16];
253 struct stripe_c *sc = ti->private;
254
255 if (!error)
256 return 0; /* I/O complete */
257
258 if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio))
259 return error;
260
261 if (error == -EOPNOTSUPP)
262 return error;
263
264 memset(major_minor, 0, sizeof(major_minor));
265 sprintf(major_minor, "%d:%d",
266 bio->bi_bdev->bd_disk->major,
267 bio->bi_bdev->bd_disk->first_minor);
268
269 /*
270 * Test to see which stripe drive triggered the event
271 * and increment error count for all stripes on that device.
272 * If the error count for a given device exceeds the threshold
273 * value we will no longer trigger any further events.
274 */
275 for (i = 0; i < sc->stripes; i++)
276 if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
277 atomic_inc(&(sc->stripe[i].error_count));
278 if (atomic_read(&(sc->stripe[i].error_count)) <
279 DM_IO_ERROR_THRESHOLD)
280 queue_work(kstriped, &sc->kstriped_ws);
281 }
282
283 return error;
284}
285
216static struct target_type stripe_target = { 286static struct target_type stripe_target = {
217 .name = "striped", 287 .name = "striped",
218 .version= {1, 0, 2}, 288 .version = {1, 1, 0},
219 .module = THIS_MODULE, 289 .module = THIS_MODULE,
220 .ctr = stripe_ctr, 290 .ctr = stripe_ctr,
221 .dtr = stripe_dtr, 291 .dtr = stripe_dtr,
222 .map = stripe_map, 292 .map = stripe_map,
293 .end_io = stripe_end_io,
223 .status = stripe_status, 294 .status = stripe_status,
224}; 295};
225 296
@@ -231,6 +302,13 @@ int __init dm_stripe_init(void)
231 if (r < 0) 302 if (r < 0)
232 DMWARN("target registration failed"); 303 DMWARN("target registration failed");
233 304
305 kstriped = create_singlethread_workqueue("kstriped");
306 if (!kstriped) {
307 DMERR("failed to create workqueue kstriped");
308 dm_unregister_target(&stripe_target);
309 return -ENOMEM;
310 }
311
234 return r; 312 return r;
235} 313}
236 314
@@ -239,5 +317,7 @@ void dm_stripe_exit(void)
239 if (dm_unregister_target(&stripe_target)) 317 if (dm_unregister_target(&stripe_target))
240 DMWARN("target unregistration failed"); 318 DMWARN("target unregistration failed");
241 319
320 destroy_workqueue(kstriped);
321
242 return; 322 return;
243} 323}