Commit a5664dad7e1a278d2915c2bf79cf42250e12d7db

Authored by Mike Snitzer
Committed by Alasdair G Kergon
1 parent 708e929513

dm ioctl: make bio or request based device type immutable

Determine whether a mapped device is bio-based or request-based when
loading its first (inactive) table and don't allow that to be changed
later.

This patch performs different device initialisation in each of the two
cases.  (We don't think it's necessary to add code to support changing
between the two types.)

Allowed md->type transitions:
  DM_TYPE_NONE to DM_TYPE_BIO_BASED
  DM_TYPE_NONE to DM_TYPE_REQUEST_BASED

We now prevent table_load from replacing the inactive table with a
conflicting type of table even after an explicit table_clear.

Introduce 'type_lock' into the struct mapped_device to protect md->type
and to prepare for the next patch that will change the queue
initialization and allocate memory while md->type_lock is held.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Acked-by: Kiyoshi Ueda <k-ueda@ct.jp.nec.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

 drivers/md/dm-ioctl.c    |   15 +++++++++++++++
 drivers/md/dm.c          |   37 ++++++++++++++++++++++++++++++-------
 drivers/md/dm.h          |    5 +++++
 include/linux/dm-ioctl.h |    4 ++--
 4 files changed, 52 insertions(+), 9 deletions(-)

Showing 4 changed files with 52 additions and 9 deletions Side-by-side Diff

drivers/md/dm-ioctl.c
... ... @@ -1189,6 +1189,21 @@
1189 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 1207 down_write(&_hash_lock);
1193 1208 hc = dm_get_mdptr(md);
1194 1209 if (!hc || hc->md != md) {
... ... @@ -125,6 +125,10 @@
125 125 unsigned long flags;
126 126  
127 127 struct request_queue *queue;
  128 + unsigned type;
  129 + /* Protect type against concurrent access. */
  130 + struct mutex type_lock;
  131 +
128 132 struct gendisk *disk;
129 133 char name[16];
130 134  
131 135  
... ... @@ -1877,8 +1881,10 @@
1877 1881 if (r < 0)
1878 1882 goto bad_minor;
1879 1883  
  1884 + md->type = DM_TYPE_NONE;
1880 1885 init_rwsem(&md->io_lock);
1881 1886 mutex_init(&md->suspend_lock);
  1887 + mutex_init(&md->type_lock);
1882 1888 spin_lock_init(&md->deferred_lock);
1883 1889 spin_lock_init(&md->barrier_error_lock);
1884 1890 rwlock_init(&md->map_lock);
... ... @@ -2130,6 +2136,30 @@
2130 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 2163 static struct mapped_device *dm_find_md(dev_t dev)
2134 2164 {
2135 2165 struct mapped_device *md;
... ... @@ -2437,13 +2467,6 @@
2437 2467 r = dm_calculate_queue_limits(table, &limits);
2438 2468 if (r) {
2439 2469 map = ERR_PTR(r);
2440   - goto out;
2441   - }
2442   -
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 2470 goto out;
2448 2471 }
2449 2472  
... ... @@ -66,6 +66,11 @@
66 66 void dm_table_free_md_mempools(struct dm_table *t);
67 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 75 * To check the return value from dm_table_find_target().
71 76 */
include/linux/dm-ioctl.h
... ... @@ -266,9 +266,9 @@
266 266 #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
267 267  
268 268 #define DM_VERSION_MAJOR 4
269   -#define DM_VERSION_MINOR 17
  269 +#define DM_VERSION_MINOR 18
270 270 #define DM_VERSION_PATCHLEVEL 0
271   -#define DM_VERSION_EXTRA "-ioctl (2010-03-05)"
  271 +#define DM_VERSION_EXTRA "-ioctl (2010-06-29)"
272 272  
273 273 /* Status bits */
274 274 #define DM_READONLY_FLAG (1 << 0) /* In/Out */