FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Device-mapper Development

 
 
LinkBack Thread Tools
 
Old 12-07-2007, 07:10 PM
"Wood, Brian J"
 
Default dm: add stripe end_io function and event trigger

From: Brian Wood <brian.j.wood@intel.com>

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@intel.com>

--- 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@intel.com

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 12-08-2007, 02:32 AM
Alasdair G Kergon
 
Default dm: add stripe end_io function and event trigger

On Fri, Dec 07, 2007 at 12:10:51PM -0800, Wood, Brian J wrote:
> +static void trigger_event(struct work_struct *work)

> + /* 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,

I'm afraid I don't understand what's going on here.

Inode/name lookups have caused dm plenty of trouble in the past from
memory and locking problems so we go out of our way to avoid them.
Only pre-existing fields (like 'name') should be used as device
references. (And how does that loop work with the error counting?)

> + /* Trigger event to let dmeventd daemon know to
> + * check device status when stripe's DSO is registered*/

(The kernel is independent of any userspace implementation, so we
avoid references to specific choices of userspace daemons. You
can however include reference examples like that in the patch header.)

> + * disconnected this sets "error == -5" */

The symbolic representation of -5 is?

Alasdair
--
agk@redhat.com

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 

Thread Tools




All times are GMT. The time now is 05:21 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org