[dm-devel] [PATCH v2 1/2] dm: prevent table type changes after initial table load

Kiyoshi Ueda k-ueda at ct.jp.nec.com
Tue May 25 11:16:22 UTC 2010


Hi Mike,

On 05/25/2010 08:46 AM +0900, Mike Snitzer wrote:
> Before table_load() stages an inactive table atomically check if its
> type conflicts with a previously established device type (md->type).
> 
> Introduce 'type_lock' in mapped_device structure and use it to protect
> md->type access.  table_load() sets md->type without concern for:
> - another table_load() racing to set conflicting md->type.
> - do_resume() making a conflicting table live.
> 
> Allowed transitions:
> UNKNOWN_MD_TYPE => BIO_BASED_MD_TYPE
> UNKNOWN_MD_TYPE => REQUEST_BASED_MD_TYPE
> 
> Once a table load occurs the DM device's type is completely immutable.
> 
> This prevents a table reload from switching the inactive table directly
> to a conflicting type (even if the table is explicitly cleared before
> load).
> 
> Signed-off-by: Mike Snitzer <snitzer at redhat.com>

I basically agree with this design.
But I have some comments.  Please see below.

By the way, I can't make enough time to review until tomorrow.
So the following comments may not be all.
Sorry for the inconvenience.


> Index: linux-2.6/drivers/md/dm-ioctl.c
> ===================================================================
> --- linux-2.6.orig/drivers/md/dm-ioctl.c
> +++ linux-2.6/drivers/md/dm-ioctl.c
> @@ -1176,12 +1176,39 @@ static int table_load(struct dm_ioctl *p
>  		goto out;
>  	}
>  
> +	/*
> +	 * Protect md->type against concurrent table loads.
> +	 * Locking strategy:
> +	 * + Leverage fact that md's type cannot change after initial table load.
> +	 *   - Only protect type in table_load() -- not in do_resume().
> +	 *
> +	 * + Protect type while working to stage an inactive table:
> +	 *   - check if table's type conflicts with md->type
> +	 *     (holding: md->type_lock)
> +	 *   - stage inactive table (hc->new_map)
> +	 *     (holding: md->type_lock + _hash_lock)
> +	 */

I think you don't need to hold md->type_lock while you set the table
to hc->new_map; If 2 tables of the same type are racing here, we can
have either table.  If they are different type, the former one will win
and the latter one will be rejected.

> +	dm_lock_md_type(md);
> +
> +	if (dm_unknown_md_type(md)) {
> +		/* initial table load, set md's type based on table's type */
> +		dm_set_md_type(md, t);
> +	} else if (!dm_md_type_matches_table(md, t)) {
> +		DMWARN("can't change device type after initial table load.");
> +		dm_table_destroy(t);
> +		dm_unlock_md_type(md);
> +		r = -EINVAL;
> +		goto out;
> +	}

So you should be able to unlock md->type_lock here.


> Index: linux-2.6/drivers/md/dm.c
> ===================================================================
> --- linux-2.6.orig/drivers/md/dm.c
> +++ linux-2.6/drivers/md/dm.c
> @@ -111,6 +111,15 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
>  #define DMF_QUEUE_IO_TO_THREAD 6
>  
>  /*
> + * Type for md->type field.
> + */
> +enum mapped_device_type {
> +	UNKNOWN_MD_TYPE,
> +	BIO_BASED_MD_TYPE,
> +	REQUEST_BASED_MD_TYPE,
> +};

You can use the defined types in drivers/md/dm.h below instead;
/*
 * Type of table and mapped_device's mempool
 */
#define DM_TYPE_NONE            0
#define DM_TYPE_BIO_BASED       1
#define DM_TYPE_REQUEST_BASED   2

Using them should make type matching easier than making another definition.
E.g. see below;

> +bool dm_md_type_matches_table(struct mapped_device *md, struct dm_table* t)
> +{
> +	if (dm_request_based_md_type(md))
> +		return dm_table_request_based(t);
> +	else if (dm_bio_based_md_type(md))
> +		return !dm_table_request_based(t);
> +
> +	return 0;
> +}

You can match type using "md->type == dm_table_get_type(t)" if you use
the already defined types above.

Thanks,
Kiyoshi Ueda




More information about the dm-devel mailing list