diff --git a/driver/device-mapper/device-mapper.h b/driver/device-mapper/device-mapper.h index 9a6a48bb0..487fd8746 100644 --- a/driver/device-mapper/device-mapper.h +++ b/driver/device-mapper/device-mapper.h @@ -46,7 +46,8 @@ typedef int (*dm_ctr_fn)(struct dm_table *t, dm_error_fn fn, void *private); typedef void (*dm_dtr_fn)(struct dm_table *t, void *c); -typedef int (*dm_map_fn)(struct buffer_head *bh, void *context); +typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context); +typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context); /* * information about a target type @@ -59,6 +60,7 @@ struct target_type { dm_ctr_fn ctr; dm_dtr_fn dtr; dm_map_fn map; + dm_err_fn err; unsigned long flags; }; diff --git a/driver/device-mapper/dm-linear.c b/driver/device-mapper/dm-linear.c index 7264e0bf3..31400d7b7 100644 --- a/driver/device-mapper/dm-linear.c +++ b/driver/device-mapper/dm-linear.c @@ -103,7 +103,7 @@ static void linear_dtr(struct dm_table *t, void *c) kfree(c); } -static int linear_map(struct buffer_head *bh, void *context) +static int linear_map(struct buffer_head *bh, int rw, void *context) { struct linear_c *lc = (struct linear_c *) context; diff --git a/driver/device-mapper/dm-target.c b/driver/device-mapper/dm-target.c index 90770ab84..f92f5f2c0 100644 --- a/driver/device-mapper/dm-target.c +++ b/driver/device-mapper/dm-target.c @@ -134,7 +134,7 @@ static void io_err_dtr(struct dm_table *t, void *c) /* empty */ } -static int io_err_map(struct buffer_head *bh, void *context) +static int io_err_map(struct buffer_head *bh, int rw, void *context) { buffer_IO_error(bh); return 0; diff --git a/driver/device-mapper/dm.c b/driver/device-mapper/dm.c index 3332ba413..1ea0e4f06 100644 --- a/driver/device-mapper/dm.c +++ b/driver/device-mapper/dm.c @@ -48,6 +48,8 @@ int _version[3] = { 0, 1, 0 }; struct io_hook { struct mapped_device *md; + struct target *target; + int rw; void (*end_io) (struct buffer_head * bh, int uptodate); void *context; }; @@ -297,6 +299,11 @@ static void dec_pending(struct buffer_head *bh, int uptodate) { struct io_hook *ih = bh->b_private; + if (!uptodate && ih->target->type->err) { + if (ih->target->type->err(bh, ih->rw, ih->target->private)) + return; + } + if (atomic_dec_and_test(&ih->md->pending)) /* nudge anyone waiting on suspend queue */ wake_up(&ih->md->wait); @@ -337,11 +344,11 @@ static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw) * do the bh mapping for a given leaf */ static inline int __map_buffer(struct mapped_device *md, - struct buffer_head *bh, int leaf) + struct buffer_head *bh, int rw, int leaf) { dm_map_fn fn; void *context; - struct io_hook *ih = 0; + struct io_hook *ih = NULL; int r; struct target *ti = md->map->targets + leaf; @@ -357,10 +364,12 @@ static inline int __map_buffer(struct mapped_device *md, return 0; ih->md = md; + ih->rw = rw; + ih->target = ti; ih->end_io = bh->b_end_io; ih->context = bh->b_private; - r = fn(bh, context); + r = fn(bh, rw, context); if (r > 0) { /* hook the end io request fn */ @@ -430,7 +439,7 @@ static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb) struct target *t = md->map->targets + __find_node(md->map, &bh); struct target_type *target = t->type; if (target->flags & TF_BMAP) { - err = target->map(&bh, t->private); + err = target->map(&bh, READ, t->private); } } up_read(&_dev_lock); @@ -473,7 +482,7 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) down_read(&_dev_lock); /* FIXME: there's still a race here */ } - if (!__map_buffer(md, bh, __find_node(md->map, bh))) + if (!__map_buffer(md, bh, rw, __find_node(md->map, bh))) goto bad; up_read(&_dev_lock);