aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBrian Wood <brian.j.wood@intel.com>2008-02-07 21:11:22 -0500
committerAlasdair G Kergon <agk@redhat.com>2008-02-07 21:11:22 -0500
commita25eb9446ad50027bc2082386e5358bedad087ed (patch)
treed9d2e5d26dbf403efa69dd52aec94bf37c82da78 /drivers
parentfb8b284806124bef250196007d7373ea3fe26194 (diff)
dm: stripe trigger event on failure
This patch adds the stripe_end_io function to process errors that might occur after an IO operation. As part of this there are a number of enhancements made to record and trigger events: - New atomic variable in struct stripe to record the number of errors each stripe volume device has experienced (could be used later with uevents to report back directly to userspace) - New workqueue/work struct setup to process the trigger_event function - New end_io function. It is here that testing for BIO error conditions take place. It determines the exact stripe that cause the error, records this in the new atomic variable, and calls the queue_work() function - New trigger_event function to process failure events. This calls dm_table_event() Signed-off-by: Brian Wood <brian.j.wood@intel.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-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}