dm ioctl: make bio or request based device type immutable
authorMike Snitzer <snitzer@redhat.com>
Thu, 12 Aug 2010 03:14:01 +0000 (04:14 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Thu, 12 Aug 2010 03:14:01 +0000 (04:14 +0100)
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(-)

drivers/md/dm-ioctl.c
drivers/md/dm.c
drivers/md/dm.h
include/linux/dm-ioctl.h

index 3fd8f0e169e72a85eb388cdc537a79dd423c319f..4702f380cb456f10bad1389576b75774dab93845 100644 (file)
@@ -1189,6 +1189,21 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
                goto out;
        }
 
+       /* Protect md->type against concurrent table loads. */
+       dm_lock_md_type(md);
+       if (dm_get_md_type(md) == DM_TYPE_NONE)
+               /* Initial table load: acquire type of table. */
+               dm_set_md_type(md, dm_table_get_type(t));
+       else if (dm_get_md_type(md) != dm_table_get_type(t)) {
+               DMWARN("can't change device type after initial table load.");
+               dm_table_destroy(t);
+               dm_unlock_md_type(md);
+               r = -EINVAL;
+               goto out;
+       }
+       dm_unlock_md_type(md);
+
+       /* stage inactive table */
        down_write(&_hash_lock);
        hc = dm_get_mdptr(md);
        if (!hc || hc->md != md) {
index f3cc5d99fe8dcd6064a6c6880de3b3a90b12b6ef..345e94c10c659f5bd8edbf92b5188f8121d1b4fd 100644 (file)
@@ -125,6 +125,10 @@ struct mapped_device {
        unsigned long flags;
 
        struct request_queue *queue;
+       unsigned type;
+       /* Protect type against concurrent access. */
+       struct mutex type_lock;
+
        struct gendisk *disk;
        char name[16];
 
@@ -1877,8 +1881,10 @@ static struct mapped_device *alloc_dev(int minor)
        if (r < 0)
                goto bad_minor;
 
+       md->type = DM_TYPE_NONE;
        init_rwsem(&md->io_lock);
        mutex_init(&md->suspend_lock);
+       mutex_init(&md->type_lock);
        spin_lock_init(&md->deferred_lock);
        spin_lock_init(&md->barrier_error_lock);
        rwlock_init(&md->map_lock);
@@ -2130,6 +2136,30 @@ int dm_create(int minor, struct mapped_device **result)
        return 0;
 }
 
+/*
+ * Functions to manage md->type.
+ * All are required to hold md->type_lock.
+ */
+void dm_lock_md_type(struct mapped_device *md)
+{
+       mutex_lock(&md->type_lock);
+}
+
+void dm_unlock_md_type(struct mapped_device *md)
+{
+       mutex_unlock(&md->type_lock);
+}
+
+void dm_set_md_type(struct mapped_device *md, unsigned type)
+{
+       md->type = type;
+}
+
+unsigned dm_get_md_type(struct mapped_device *md)
+{
+       return md->type;
+}
+
 static struct mapped_device *dm_find_md(dev_t dev)
 {
        struct mapped_device *md;
@@ -2440,13 +2470,6 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
                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");
-               goto out;
-       }
-
        map = __bind(md, table, &limits);
 
 out:
index 8223671e4901b3e1b8fe3fc1bac93e49b8d7d74b..1db782530ce67beeedb791f2a2fb8a4431c6dead 100644 (file)
@@ -66,6 +66,11 @@ int dm_table_alloc_md_mempools(struct dm_table *t);
 void dm_table_free_md_mempools(struct dm_table *t);
 struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
 
+void dm_lock_md_type(struct mapped_device *md);
+void dm_unlock_md_type(struct mapped_device *md);
+void dm_set_md_type(struct mapped_device *md, unsigned type);
+unsigned dm_get_md_type(struct mapped_device *md);
+
 /*
  * To check the return value from dm_table_find_target().
  */
index 2c445e11379026041cb795844711379546da2a20..43b2de17449b5ed8fda18b94b84cf402109ec066 100644 (file)
@@ -266,9 +266,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       17
+#define DM_VERSION_MINOR       18
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2010-03-05)"
+#define DM_VERSION_EXTRA       "-ioctl (2010-06-29)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */