diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/dm-ioctl.c | 15 | ||||
-rw-r--r-- | drivers/md/dm.c | 37 | ||||
-rw-r--r-- | drivers/md/dm.h | 5 |
3 files changed, 50 insertions, 7 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 3fd8f0e169e7..4702f380cb45 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1189,6 +1189,21 @@ static int table_load(struct dm_ioctl *param, size_t param_size) | |||
1189 | goto out; | 1189 | goto out; |
1190 | } | 1190 | } |
1191 | 1191 | ||
1192 | /* Protect md->type against concurrent table loads. */ | ||
1193 | dm_lock_md_type(md); | ||
1194 | if (dm_get_md_type(md) == DM_TYPE_NONE) | ||
1195 | /* Initial table load: acquire type of table. */ | ||
1196 | dm_set_md_type(md, dm_table_get_type(t)); | ||
1197 | else if (dm_get_md_type(md) != dm_table_get_type(t)) { | ||
1198 | DMWARN("can't change device type after initial table load."); | ||
1199 | dm_table_destroy(t); | ||
1200 | dm_unlock_md_type(md); | ||
1201 | r = -EINVAL; | ||
1202 | goto out; | ||
1203 | } | ||
1204 | dm_unlock_md_type(md); | ||
1205 | |||
1206 | /* stage inactive table */ | ||
1192 | down_write(&_hash_lock); | 1207 | down_write(&_hash_lock); |
1193 | hc = dm_get_mdptr(md); | 1208 | hc = dm_get_mdptr(md); |
1194 | if (!hc || hc->md != md) { | 1209 | if (!hc || hc->md != md) { |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f3cc5d99fe8d..345e94c10c65 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -125,6 +125,10 @@ struct mapped_device { | |||
125 | unsigned long flags; | 125 | unsigned long flags; |
126 | 126 | ||
127 | struct request_queue *queue; | 127 | struct request_queue *queue; |
128 | unsigned type; | ||
129 | /* Protect type against concurrent access. */ | ||
130 | struct mutex type_lock; | ||
131 | |||
128 | struct gendisk *disk; | 132 | struct gendisk *disk; |
129 | char name[16]; | 133 | char name[16]; |
130 | 134 | ||
@@ -1877,8 +1881,10 @@ static struct mapped_device *alloc_dev(int minor) | |||
1877 | if (r < 0) | 1881 | if (r < 0) |
1878 | goto bad_minor; | 1882 | goto bad_minor; |
1879 | 1883 | ||
1884 | md->type = DM_TYPE_NONE; | ||
1880 | init_rwsem(&md->io_lock); | 1885 | init_rwsem(&md->io_lock); |
1881 | mutex_init(&md->suspend_lock); | 1886 | mutex_init(&md->suspend_lock); |
1887 | mutex_init(&md->type_lock); | ||
1882 | spin_lock_init(&md->deferred_lock); | 1888 | spin_lock_init(&md->deferred_lock); |
1883 | spin_lock_init(&md->barrier_error_lock); | 1889 | spin_lock_init(&md->barrier_error_lock); |
1884 | rwlock_init(&md->map_lock); | 1890 | rwlock_init(&md->map_lock); |
@@ -2130,6 +2136,30 @@ int dm_create(int minor, struct mapped_device **result) | |||
2130 | return 0; | 2136 | return 0; |
2131 | } | 2137 | } |
2132 | 2138 | ||
2139 | /* | ||
2140 | * Functions to manage md->type. | ||
2141 | * All are required to hold md->type_lock. | ||
2142 | */ | ||
2143 | void dm_lock_md_type(struct mapped_device *md) | ||
2144 | { | ||
2145 | mutex_lock(&md->type_lock); | ||
2146 | } | ||
2147 | |||
2148 | void dm_unlock_md_type(struct mapped_device *md) | ||
2149 | { | ||
2150 | mutex_unlock(&md->type_lock); | ||
2151 | } | ||
2152 | |||
2153 | void dm_set_md_type(struct mapped_device *md, unsigned type) | ||
2154 | { | ||
2155 | md->type = type; | ||
2156 | } | ||
2157 | |||
2158 | unsigned dm_get_md_type(struct mapped_device *md) | ||
2159 | { | ||
2160 | return md->type; | ||
2161 | } | ||
2162 | |||
2133 | static struct mapped_device *dm_find_md(dev_t dev) | 2163 | static struct mapped_device *dm_find_md(dev_t dev) |
2134 | { | 2164 | { |
2135 | struct mapped_device *md; | 2165 | struct mapped_device *md; |
@@ -2440,13 +2470,6 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) | |||
2440 | goto out; | 2470 | goto out; |
2441 | } | 2471 | } |
2442 | 2472 | ||
2443 | /* cannot change the device type, once a table is bound */ | ||
2444 | if (md->map && | ||
2445 | (dm_table_get_type(md->map) != dm_table_get_type(table))) { | ||
2446 | DMWARN("can't change the device type after a table is bound"); | ||
2447 | goto out; | ||
2448 | } | ||
2449 | |||
2450 | map = __bind(md, table, &limits); | 2473 | map = __bind(md, table, &limits); |
2451 | 2474 | ||
2452 | out: | 2475 | out: |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 8223671e4901..1db782530ce6 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -66,6 +66,11 @@ int dm_table_alloc_md_mempools(struct dm_table *t); | |||
66 | void dm_table_free_md_mempools(struct dm_table *t); | 66 | void dm_table_free_md_mempools(struct dm_table *t); |
67 | struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); | 67 | struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); |
68 | 68 | ||
69 | void dm_lock_md_type(struct mapped_device *md); | ||
70 | void dm_unlock_md_type(struct mapped_device *md); | ||
71 | void dm_set_md_type(struct mapped_device *md, unsigned type); | ||
72 | unsigned dm_get_md_type(struct mapped_device *md); | ||
73 | |||
69 | /* | 74 | /* |
70 | * To check the return value from dm_table_find_target(). | 75 | * To check the return value from dm_table_find_target(). |
71 | */ | 76 | */ |