Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 84591
b: refs/heads/master
c: a25eb94
h: refs/heads/master
i:
  84589: ee540cd
  84587: c0beb04
  84583: 704fa41
  84575: 9b22f19
v: v3
  • Loading branch information
Brian Wood authored and Alasdair G Kergon committed Feb 8, 2008
1 parent 481e4b2 commit d12cd1c
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fb8b284806124bef250196007d7373ea3fe26194
refs/heads/master: a25eb9446ad50027bc2082386e5358bedad087ed
82 changes: 81 additions & 1 deletion trunk/drivers/md/dm-stripe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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,
};

Expand All @@ -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;
}

Expand All @@ -239,5 +317,7 @@ void dm_stripe_exit(void)
if (dm_unregister_target(&stripe_target))
DMWARN("target unregistration failed");

destroy_workqueue(kstriped);

return;
}

0 comments on commit d12cd1c

Please sign in to comment.