[PATCH 1/2] dm: add stripe end_io function and event trigger

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [DM Crypt]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite Discussion]     [KDE Users]     [Fedora Docs]

  Powered by Linux