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>
- struct stripe stripe[0];
+ /* 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 +127,7 @@
return -ENXIO;