commit 1327d9674e235b4c3004034298ba4863d038ee88 Author: S.Çağlar Onur Date: Fri Mar 19 15:12:59 2010 -0400 support_barriers_on_single_device_dm_devices.patch diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 17753d8..cda44f6 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -123,6 +123,7 @@ static struct target_type linear_target = { .map = linear_map, .status = linear_status, .ioctl = linear_ioctl, + .features = DM_TARGET_SUPPORTS_BARRIERS, }; int __init dm_linear_init(void) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 2fc199b..e540f57 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -38,6 +38,8 @@ struct dm_table { sector_t *highs; struct dm_target *targets; + unsigned barriers_supported:1; + /* * Indicates the rw permissions for the new logical * device. This should be a combination of FMODE_READ @@ -221,6 +223,7 @@ int dm_table_create(struct dm_table **result, int mode, memset(t, 0, sizeof(*t)); INIT_LIST_HEAD(&t->devices); atomic_set(&t->holders, 1); + t->barriers_supported = 1; if (!num_targets) num_targets = KEYS_PER_NODE; @@ -765,6 +768,10 @@ int dm_table_add_target(struct dm_table *t, const char *type, /* FIXME: the plan is to combine high here and then have * the merge fn apply the target level restrictions. */ combine_restrictions_low(&t->limits, &tgt->limits); + + if (!(tgt->type->features & DM_TARGET_SUPPORTS_BARRIERS)) + t->barriers_supported = 0; + return 0; bad: @@ -809,6 +816,12 @@ int dm_table_complete(struct dm_table *t) check_for_valid_limits(&t->limits); + /* + * We only support barriers if there is exactly one underlying device. + */ + if (!list_is_singular(&t->devices)) + t->barriers_supported = 0; + /* how many indexes will the btree have ? */ leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); @@ -1033,6 +1046,11 @@ struct mapped_device *dm_table_get_md(struct dm_table *t) return t->md; } +int dm_table_barrier_ok(struct dm_table *t) +{ + return t->barriers_supported; +} +EXPORT_SYMBOL(dm_table_barrier_ok); EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 12ecab3..bdf5107 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -781,6 +781,12 @@ static void __split_bio(struct mapped_device *md, struct bio *bio) return; } + if (unlikely(bio_barrier(bio) && !dm_table_barrier_ok(ci.map))) { + dm_table_put(ci.map); + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return; + } + ci.md = md; ci.bio = bio; ci.io = alloc_io(md); @@ -814,15 +820,6 @@ static int dm_request(request_queue_t *q, struct bio *bio) int rw = bio_data_dir(bio); struct mapped_device *md = q->queuedata; - /* - * There is no use in forwarding any barrier request since we can't - * guarantee it is (or can be) handled by the targets correctly. - */ - if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); - return 0; - } - down_read(&md->io_lock); disk_stat_inc(dm_disk(md), ios[rw]); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index e71b22d..a67e8b7 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -80,6 +80,7 @@ int dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); void dm_table_unplug_all(struct dm_table *t); int dm_table_flush_all(struct dm_table *t); +int dm_table_barrier_ok(struct dm_table *t); /*----------------------------------------------------------------- * A registry of target types. diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 499f537..6bc9120 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -89,9 +89,15 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start, void dm_put_device(struct dm_target *ti, struct dm_dev *d); /* + * Target features + */ +#define DM_TARGET_SUPPORTS_BARRIERS 0x00000001 + +/* * Information about a target type */ struct target_type { + uint64_t features; const char *name; struct module *module; unsigned version[3]; diff --git a/include/linux/list.h b/include/linux/list.h index f29fc9c..55051eb 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -319,6 +319,15 @@ static inline int list_empty_careful(const struct list_head *head) return (next == head) && (next == head->prev); } +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + static inline void __list_splice(struct list_head *list, struct list_head *head) {