From: Brian Wood <brian.j.wood@xxxxxxxxx> 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 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 trigger_event function to process failure events. This will determine the exact stripe that cause the IO error, record the error and call dm_table_event() - With this change Alasdair requested that the version number be incremented Signed-off-by: Brian Wood <brian.j.wood@xxxxxxxxx> --- linux-2.6.24-rc3/drivers/md/dm-stripe.c 2007-12-06 01:47:11.000000000 -0800 +++ linux-2.6.24-rc3.mod/drivers/md/dm-stripe.c 2007-12-06 01:45:25.000000000 -0800 @@ -12,10 +12,14 @@ #include <linux/bio.h> #include <linux/slab.h> #include <linux/log2.h> +#include <linux/namei.h> #define DM_MSG_PREFIX "striped" +#define IO_ERROR_COUNT 15 +#define DEV_STR_LEN 15 struct stripe { + atomic_t error_count; struct dm_dev *dev; sector_t physical_start; }; @@ -30,9 +34,71 @@ 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]; }; +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) +{ + int i, len; + char dev_path[DEV_STR_LEN]; + struct stripe_c *sc = container_of(work, struct stripe_c, kstriped_ws); + struct nameidata nd; + struct inode *inode; + + /* Test to see which stripe drive triggered the event. */ + for (i = 0; i < sc->stripes; i++) { + memset(dev_path, 0, DEV_STR_LEN); + memcpy(dev_path, "/dev/", len = strlen("/dev/")); + /* Copy name of the drive stored in the gendisk structure + * (this is the same name as what is stored in the + * /proc and /sysfs filesystems */ + memcpy(dev_path+len, + sc->stripe[i].dev->bdev->bd_disk->disk_name, + strlen(sc->stripe[i].dev->bdev->bd_disk->disk_name)); + + /* Check to see if path can be used to + * fill nameidata structure */ + if (path_lookup(dev_path, LOOKUP_FOLLOW, &nd)) { + atomic_inc(&(sc->stripe[i].error_count)); + goto out; + } + + /* Next check to see if device has an inode entry + * (this is where it will likely find the disabled device) */ + inode = nd.dentry->d_inode; + if (!inode) { + atomic_inc(&(sc->stripe[i].error_count)); + goto out; + } + + /* Finally as a last check, see if the inode mode is set + * to be a block device, record error if not */ + if (!S_ISBLK(inode->i_mode)) + atomic_inc(&(sc->stripe[i].error_count)); + +out: + /* We don't want to generate hundreds of work queue calls + * when IO errors occur for a device, so we only queue up the + * first IO_ERROR_COUNT for a given underlying hardware device. + * After that point is reached we still record the errors, + * but won't call dm_table_event() to report them. */ + if (atomic_read(&(sc->stripe[i].error_count)) < IO_ERROR_COUNT) + dm_table_event(sc->ti->table); + } +} + static inline struct stripe_c *alloc_context(unsigned int stripes) { size_t len; @@ -63,6 +129,7 @@ static int get_stripe(struct dm_target * return -ENXIO; sc->stripe[stripe].physical_start = start; + return 0; } @@ -135,6 +202,12 @@ static int stripe_ctr(struct dm_target * return -ENOMEM; } + /* Initialize the work_struct */ + 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; @@ -149,7 +222,6 @@ static int stripe_ctr(struct dm_target * */ for (i = 0; i < stripes; i++) { argv += 2; - r = get_stripe(ti, sc, i, argv); if (r < 0) { ti->error = "Couldn't parse stripe destination"; @@ -158,9 +230,16 @@ static int stripe_ctr(struct dm_target * kfree(sc); return r; } + /* Initialize error_count */ + atomic_set(&(sc->stripe[i].error_count), 0); } ti->private = sc; + + /* Trigger event to let dmeventd daemon know to + * check device status when stripe's DSO is registered*/ + queue_work(kstriped, &sc->kstriped_ws); + return 0; } @@ -172,6 +251,7 @@ static void stripe_dtr(struct dm_target for (i = 0; i < sc->stripes; i++) dm_put_device(ti, sc->stripe[i].dev); + flush_workqueue(kstriped); kfree(sc); } @@ -213,13 +293,37 @@ static int stripe_status(struct dm_targe return 0; } +static int stripe_end_io(struct dm_target *ti, struct bio *bio, + int error, union map_info *map_context) +{ + struct stripe_c *sc = (struct stripe_c *) ti->private; + + if (!error) + return 0; /* I/O complete */ + + if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) + return error; + + if (error == -EOPNOTSUPP) + return error; + + /* Error not caught above, trigger event. + * For example, if member device gets + * disconnected this sets "error == -5" */ + if (error < 0) + queue_work(kstriped, &sc->kstriped_ws); + + return error; +} + static struct target_type stripe_target = { .name = "striped", - .version= {1, 0, 2}, + .version = {1, 1, 2}, .module = THIS_MODULE, .ctr = stripe_ctr, .dtr = stripe_dtr, .map = stripe_map, + .end_io = stripe_end_io, .status = stripe_status, }; @@ -231,6 +335,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 +350,7 @@ void dm_stripe_exit(void) if (dm_unregister_target(&stripe_target)) DMWARN("target unregistration failed"); + destroy_workqueue(kstriped); + return; } Brian Wood Software Engineer Intel Corp., Manageability & Platform Software Division brian.j.wood@xxxxxxxxx
Attachment:
dm-stripe-end_io-event-trigger.patch
Description: dm-stripe-end_io-event-trigger.patch
-- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel