Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a25eb9446ad50027bc2082386e5358bedad087ed
Commit:     a25eb9446ad50027bc2082386e5358bedad087ed
Parent:     fb8b284806124bef250196007d7373ea3fe26194
Author:     Brian Wood <[EMAIL PROTECTED]>
AuthorDate: Fri Feb 8 02:11:22 2008 +0000
Committer:  Alasdair G Kergon <[EMAIL PROTECTED]>
CommitDate: Fri Feb 8 02:11:22 2008 +0000

    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 <[EMAIL PROTECTED]>
    Signed-off-by: Alasdair G Kergon <[EMAIL PROTECTED]>
---
 drivers/md/dm-stripe.c |   82 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 81 insertions(+), 1 deletions(-)

diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 969944a..7c5e2a0 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -14,10 +14,13 @@
 #include <linux/log2.h>
 
 #define DM_MSG_PREFIX "striped"
+#define DM_IO_ERROR_THRESHOLD 15
 
 struct stripe {
        struct dm_dev *dev;
        sector_t physical_start;
+
+       atomic_t error_count;
 };
 
 struct stripe_c {
@@ -30,9 +33,29 @@ struct stripe_c {
        uint32_t chunk_shift;
        sector_t chunk_mask;
 
+       /* Needed for handling events */
+       struct dm_target *ti;
+
+       /* Work struct used for triggering events*/
+       struct work_struct kstriped_ws;
+
        struct stripe stripe[0];
 };
 
+static struct workqueue_struct *kstriped;
+
+/*
+ * An event is triggered whenever a drive
+ * drops out of a stripe volume.
+ */
+static void trigger_event(struct work_struct *work)
+{
+       struct stripe_c *sc = container_of(work, struct stripe_c, kstriped_ws);
+
+       dm_table_event(sc->ti->table);
+
+}
+
 static inline struct stripe_c *alloc_context(unsigned int stripes)
 {
        size_t len;
@@ -63,6 +86,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c 
*sc,
                return -ENXIO;
 
        sc->stripe[stripe].physical_start = start;
+
        return 0;
 }
 
@@ -135,6 +159,11 @@ static int stripe_ctr(struct dm_target *ti, unsigned int 
argc, char **argv)
                return -ENOMEM;
        }
 
+       INIT_WORK(&sc->kstriped_ws, trigger_event);
+
+       /* Set pointer to dm target; used in trigger_event */
+       sc->ti = ti;
+
        sc->stripes = stripes;
        sc->stripe_width = width;
        ti->split_io = chunk_size;
@@ -158,9 +187,11 @@ static int stripe_ctr(struct dm_target *ti, unsigned int 
argc, char **argv)
                        kfree(sc);
                        return r;
                }
+               atomic_set(&(sc->stripe[i].error_count), 0);
        }
 
        ti->private = sc;
+
        return 0;
 }
 
@@ -172,6 +203,7 @@ static void stripe_dtr(struct dm_target *ti)
        for (i = 0; i < sc->stripes; i++)
                dm_put_device(ti, sc->stripe[i].dev);
 
+       flush_workqueue(kstriped);
        kfree(sc);
 }
 
@@ -213,13 +245,52 @@ static int stripe_status(struct dm_target *ti,
        return 0;
 }
 
+static int stripe_end_io(struct dm_target *ti, struct bio *bio,
+                        int error, union map_info *map_context)
+{
+       unsigned i;
+       char major_minor[16];
+       struct stripe_c *sc = ti->private;
+
+       if (!error)
+               return 0; /* I/O complete */
+
+       if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio))
+               return error;
+
+       if (error == -EOPNOTSUPP)
+               return error;
+
+       memset(major_minor, 0, sizeof(major_minor));
+       sprintf(major_minor, "%d:%d",
+               bio->bi_bdev->bd_disk->major,
+               bio->bi_bdev->bd_disk->first_minor);
+
+       /*
+        * Test to see which stripe drive triggered the event
+        * and increment error count for all stripes on that device.
+        * If the error count for a given device exceeds the threshold
+        * value we will no longer trigger any further events.
+        */
+       for (i = 0; i < sc->stripes; i++)
+               if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
+                       atomic_inc(&(sc->stripe[i].error_count));
+                       if (atomic_read(&(sc->stripe[i].error_count)) <
+                           DM_IO_ERROR_THRESHOLD)
+                               queue_work(kstriped, &sc->kstriped_ws);
+               }
+
+       return error;
+}
+
 static struct target_type stripe_target = {
        .name   = "striped",
-       .version= {1, 0, 2},
+       .version = {1, 1, 0},
        .module = THIS_MODULE,
        .ctr    = stripe_ctr,
        .dtr    = stripe_dtr,
        .map    = stripe_map,
+       .end_io = stripe_end_io,
        .status = stripe_status,
 };
 
@@ -231,6 +302,13 @@ int __init dm_stripe_init(void)
        if (r < 0)
                DMWARN("target registration failed");
 
+       kstriped = create_singlethread_workqueue("kstriped");
+       if (!kstriped) {
+               DMERR("failed to create workqueue kstriped");
+               dm_unregister_target(&stripe_target);
+               return -ENOMEM;
+       }
+
        return r;
 }
 
@@ -239,5 +317,7 @@ void dm_stripe_exit(void)
        if (dm_unregister_target(&stripe_target))
                DMWARN("target unregistration failed");
 
+       destroy_workqueue(kstriped);
+
        return;
 }
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to