[dm-devel] [PATCH] dm: also check for conflicting table type in dm_table_set_type
Mike Snitzer
snitzer at redhat.com
Thu May 20 22:26:26 UTC 2010
Factorize live table type compatibility check into
dm_table_type_matches_live_table(). Catching a conflicting table type
early, during table load, avoids failing during resume -- which always
leaves the DM device suspended.
So also check type during dm_table_set_type() -- which happens as part
of a table load. But preserve the existing check during resume, in
dm_swap_table(), because a racing table load could stage an inactive
table that conflicts with the table type that dm_swap_table() is about
to make live:
table_load() for bio-based do_resume() for rq-based
-----------------------------------------------------------------
dm_table_type_matches_live_table(t)
down_write(_hash_lock)
new_map = hc->new_map
up_write(_hash_lock)
down_write(_hash_lock)
hc->new_map = t
up_write(_hash_lock)
dm_swap_table(md, new_map)
dm_table_type_matches_live_table(t)
__bind(md, new_map)
Signed-off-by: Mike Snitzer <snitzer at redhat.com>
---
drivers/md/dm-table.c | 24 +++++++++++++++++++++++-
drivers/md/dm.c | 6 +-----
drivers/md/dm.h | 1 +
3 files changed, 25 insertions(+), 6 deletions(-)
Index: linux-2.6/drivers/md/dm-table.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-table.c
+++ linux-2.6/drivers/md/dm-table.c
@@ -803,7 +803,7 @@ int dm_table_set_type(struct dm_table *t
if (bio_based) {
/* We must use this table as bio-based */
t->type = DM_TYPE_BIO_BASED;
- return 0;
+ goto finish;
}
BUG_ON(!request_based); /* No targets in this table */
@@ -831,6 +831,10 @@ int dm_table_set_type(struct dm_table *t
t->type = DM_TYPE_REQUEST_BASED;
+finish:
+ if (!dm_table_type_matches_live_table(t))
+ return -EINVAL;
+
return 0;
}
@@ -839,6 +843,24 @@ unsigned dm_table_get_type(struct dm_tab
return t->type;
}
+int dm_table_type_matches_live_table(struct dm_table *t)
+{
+ int r = 1;
+ struct dm_table *live_table = NULL;
+
+ live_table = dm_get_live_table(t->md);
+ if (!live_table)
+ return 1; /* no live table, return success */
+
+ if (dm_table_get_type(live_table) != dm_table_get_type(t)) {
+ DMWARN("can't change the device type after a table is bound");
+ r = 0;
+ }
+ dm_table_put(live_table);
+
+ return r;
+}
+
bool dm_table_request_based(struct dm_table *t)
{
return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED;
Index: linux-2.6/drivers/md/dm.c
===================================================================
--- linux-2.6.orig/drivers/md/dm.c
+++ linux-2.6/drivers/md/dm.c
@@ -2403,12 +2403,8 @@ struct dm_table *dm_swap_table(struct ma
goto out;
}
- /* cannot change the device type, once a table is bound */
- if (md->map &&
- (dm_table_get_type(md->map) != dm_table_get_type(table))) {
- DMWARN("can't change the device type after a table is bound");
+ if (!dm_table_type_matches_live_table(table))
goto out;
- }
map = __bind(md, table, &limits);
Index: linux-2.6/drivers/md/dm.h
===================================================================
--- linux-2.6.orig/drivers/md/dm.h
+++ linux-2.6/drivers/md/dm.h
@@ -61,6 +61,7 @@ int dm_table_any_congested(struct dm_tab
int dm_table_any_busy_target(struct dm_table *t);
int dm_table_set_type(struct dm_table *t);
unsigned dm_table_get_type(struct dm_table *t);
+int dm_table_type_matches_live_table(struct dm_table *t);
bool dm_table_request_based(struct dm_table *t);
int dm_table_alloc_md_mempools(struct dm_table *t);
void dm_table_free_md_mempools(struct dm_table *t);
More information about the dm-devel
mailing list