diff mbox series

dm: fix iterate_device sanity check

Message ID 20210202033528.76166-1-jefflexu@linux.alibaba.com (mailing list archive)
State Accepted, archived
Delegated to: Mike Snitzer
Headers show
Series dm: fix iterate_device sanity check | expand

Commit Message

Jingbo Xu Feb. 2, 2021, 3:35 a.m. UTC
According to the definition of dm_iterate_devices_fn:
 * This function must iterate through each section of device used by the
 * target until it encounters a non-zero return code, which it then returns.
 * Returns zero if no callout returned non-zero.

For some target type (e.g., dm-stripe), one call of iterate_devices() may
iterate multiple underlying devices internally, in which case a non-zero
return code returned by iterate_devices_callout_fn will stop the iteration
in advance.

Thus if we want to ensure that _all_ underlying devices support some kind of
attribute, the iteration structure like dm_table_supports_nowait() should be
used, while the input iterate_devices_callout_fn should handle the 'not
support' semantics. On the opposite, the iteration structure like
dm_table_any_device_attribute() should be used if _any_ underlying device
supporting this attibute is sufficient. In this case, the input
iterate_devices_callout_fn should handle the 'support' semantics.

Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
Cc: stable@vger.kernel.org
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
---
 drivers/md/dm-table.c | 84 ++++++++++++++++++++++---------------------
 drivers/md/dm.c       |  2 +-
 drivers/md/dm.h       |  2 +-
 3 files changed, 46 insertions(+), 42 deletions(-)

Comments

Jingbo Xu Feb. 2, 2021, 4:40 a.m. UTC | #1
dm_table_supports_dax_write_cache() is remained untouched, since I'm not
sure if the semantics requires that 'any underlying device' or 'all
underlying devices' supporting dax_write_cache. At least it seems that
'any underlying device' is sufficient from the current code.

On 2/2/21 11:35 AM, Jeffle Xu wrote:
> According to the definition of dm_iterate_devices_fn:
>  * This function must iterate through each section of device used by the
>  * target until it encounters a non-zero return code, which it then returns.
>  * Returns zero if no callout returned non-zero.
> 
> For some target type (e.g., dm-stripe), one call of iterate_devices() may
> iterate multiple underlying devices internally, in which case a non-zero
> return code returned by iterate_devices_callout_fn will stop the iteration
> in advance.
> 
> Thus if we want to ensure that _all_ underlying devices support some kind of
> attribute, the iteration structure like dm_table_supports_nowait() should be
> used, while the input iterate_devices_callout_fn should handle the 'not
> support' semantics. On the opposite, the iteration structure like
> dm_table_any_device_attribute() should be used if _any_ underlying device
> supporting this attibute is sufficient. In this case, the input
> iterate_devices_callout_fn should handle the 'support' semantics.
> 
> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
> ---
>  drivers/md/dm-table.c | 84 ++++++++++++++++++++++---------------------
>  drivers/md/dm.c       |  2 +-
>  drivers/md/dm.h       |  2 +-
>  3 files changed, 46 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
> index 4acf2342f7ad..53dcbf75eda9 100644
> --- a/drivers/md/dm-table.c
> +++ b/drivers/md/dm-table.c
> @@ -820,24 +820,24 @@ void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type)
>  EXPORT_SYMBOL_GPL(dm_table_set_type);
>  
>  /* validate the dax capability of the target device span */
> -int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
> +int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
>  			sector_t start, sector_t len, void *data)
>  {
>  	int blocksize = *(int *) data, id;
>  	bool rc;
>  
>  	id = dax_read_lock();
> -	rc = dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
> +	rc = !dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
>  	dax_read_unlock(id);
>  
>  	return rc;
>  }
>  
>  /* Check devices support synchronous DAX */
> -static int device_dax_synchronous(struct dm_target *ti, struct dm_dev *dev,
> +static int device_not_dax_synchronous_capable(struct dm_target *ti, struct dm_dev *dev,
>  				  sector_t start, sector_t len, void *data)
>  {
> -	return dev->dax_dev && dax_synchronous(dev->dax_dev);
> +	return !dev->dax_dev || !dax_synchronous(dev->dax_dev);
>  }
>  
>  bool dm_table_supports_dax(struct dm_table *t,
> @@ -854,7 +854,7 @@ bool dm_table_supports_dax(struct dm_table *t,
>  			return false;
>  
>  		if (!ti->type->iterate_devices ||
> -		    !ti->type->iterate_devices(ti, iterate_fn, blocksize))
> +		    ti->type->iterate_devices(ti, iterate_fn, blocksize))
>  			return false;
>  	}
>  
> @@ -925,7 +925,7 @@ static int dm_table_determine_type(struct dm_table *t)
>  verify_bio_based:
>  		/* We must use this table as bio-based */
>  		t->type = DM_TYPE_BIO_BASED;
> -		if (dm_table_supports_dax(t, device_supports_dax, &page_size) ||
> +		if (dm_table_supports_dax(t, device_not_dax_capable, &page_size) ||
>  		    (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) {
>  			t->type = DM_TYPE_DAX_BIO_BASED;
>  		}
> @@ -1595,12 +1595,12 @@ static int dm_table_supports_dax_write_cache(struct dm_table *t)
>  	return false;
>  }
>  
> -static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev,
> +static int device_is_rot(struct dm_target *ti, struct dm_dev *dev,
>  			    sector_t start, sector_t len, void *data)
>  {
>  	struct request_queue *q = bdev_get_queue(dev->bdev);
>  
> -	return q && blk_queue_nonrot(q);
> +	return q && !blk_queue_nonrot(q);
>  }
>  
>  static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
> @@ -1611,8 +1611,8 @@ static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
>  	return q && !blk_queue_add_random(q);
>  }
>  
> -static bool dm_table_all_devices_attribute(struct dm_table *t,
> -					   iterate_devices_callout_fn func)
> +static bool dm_table_any_device_attribute(struct dm_table *t,
> +					  iterate_devices_callout_fn func)
>  {
>  	struct dm_target *ti;
>  	unsigned i;
> @@ -1620,12 +1620,12 @@ static bool dm_table_all_devices_attribute(struct dm_table *t,
>  	for (i = 0; i < dm_table_get_num_targets(t); i++) {
>  		ti = dm_table_get_target(t, i);
>  
> -		if (!ti->type->iterate_devices ||
> -		    !ti->type->iterate_devices(ti, func, NULL))
> -			return false;
> +		if (ti->type->iterate_devices &&
> +		    ti->type->iterate_devices(ti, func, NULL))
> +			return true;
>  	}
>  
> -	return true;
> +	return false;
>  }
>  
>  static int device_not_write_same_capable(struct dm_target *ti, struct dm_dev *dev,
> @@ -1780,26 +1780,25 @@ static int device_requires_stable_pages(struct dm_target *ti,
>  }
>  
>  /*
> - * If any underlying device requires stable pages, a table must require
> - * them as well.  Only targets that support iterate_devices are considered:
> - * don't want error, zero, etc to require stable pages.
> + * type->iterate_devices() should be called when the sanity check needs to
> + * iterate and check all underlying data devices. iterate_devices() will
> + * iterate all underlying data devices until it encounters a non-zero return
> + * code, returned by whether the input iterate_devices_callout_fn, or
> + * iterate_devices() itself internally.
> + *
> + * For some target type (e.g., dm-stripe), one call of iterate_devices() may
> + * iterate multiple underlying devices internally, in which case a non-zero
> + * return code returned by iterate_devices_callout_fn will stop the iteration
> + * in advance.
> + *
> + * Thus if we want to ensure that _all_ underlying devices support some kind of
> + * attribute, the iteration structure like dm_table_supports_nowait() should be
> + * used, while the input iterate_devices_callout_fn should handle the 'not
> + * support' semantics. On the opposite, the iteration structure like
> + * dm_table_any_device_attribute() should be used if _any_ underlying device
> + * supporting this attibute is sufficient. In this case, the input
> + * iterate_devices_callout_fn should handle the 'support' semantics.
>   */
> -static bool dm_table_requires_stable_pages(struct dm_table *t)
> -{
> -	struct dm_target *ti;
> -	unsigned i;
> -
> -	for (i = 0; i < dm_table_get_num_targets(t); i++) {
> -		ti = dm_table_get_target(t, i);
> -
> -		if (ti->type->iterate_devices &&
> -		    ti->type->iterate_devices(ti, device_requires_stable_pages, NULL))
> -			return true;
> -	}
> -
> -	return false;
> -}
> -
>  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  			       struct queue_limits *limits)
>  {
> @@ -1837,9 +1836,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  	}
>  	blk_queue_write_cache(q, wc, fua);
>  
> -	if (dm_table_supports_dax(t, device_supports_dax, &page_size)) {
> +	if (dm_table_supports_dax(t, device_not_dax_capable, &page_size)) {
>  		blk_queue_flag_set(QUEUE_FLAG_DAX, q);
> -		if (dm_table_supports_dax(t, device_dax_synchronous, NULL))
> +		if (dm_table_supports_dax(t, device_not_dax_synchronous_capable, NULL))
>  			set_dax_synchronous(t->md->dax_dev);
>  	}
>  	else
> @@ -1849,10 +1848,10 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  		dax_write_cache(t->md->dax_dev, true);
>  
>  	/* Ensure that all underlying devices are non-rotational. */
> -	if (dm_table_all_devices_attribute(t, device_is_nonrot))
> -		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
> -	else
> +	if (dm_table_any_device_attribute(t, device_is_rot))
>  		blk_queue_flag_clear(QUEUE_FLAG_NONROT, q);
> +	else
> +		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
>  
>  	if (!dm_table_supports_write_same(t))
>  		q->limits.max_write_same_sectors = 0;
> @@ -1864,8 +1863,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  	/*
>  	 * Some devices don't use blk_integrity but still want stable pages
>  	 * because they do their own checksumming.
> +	 * If any underlying device requires stable pages, a table must require
> +	 * them as well.  Only targets that support iterate_devices are considered:
> +	 * don't want error, zero, etc to require stable pages.
>  	 */
> -	if (dm_table_requires_stable_pages(t))
> +	if (dm_table_any_device_attribute(t, device_requires_stable_pages))
>  		blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, q);
>  	else
>  		blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, q);
> @@ -1876,8 +1878,10 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  	 * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not
>  	 * have it set.
>  	 */
> -	if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
> +	if (dm_table_any_device_attribute(t, device_is_not_random))
>  		blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
> +	else
> +		blk_queue_flag_set(QUEUE_FLAG_ADD_RANDOM, q);
>  
>  	/*
>  	 * For a zoned target, the number of zones should be updated for the
> diff --git a/drivers/md/dm.c b/drivers/md/dm.c
> index 7bac564f3faa..8a3d73efb9dd 100644
> --- a/drivers/md/dm.c
> +++ b/drivers/md/dm.c
> @@ -1128,7 +1128,7 @@ static bool dm_dax_supported(struct dax_device *dax_dev, struct block_device *bd
>  	if (!map)
>  		goto out;
>  
> -	ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
> +	ret = dm_table_supports_dax(map, device_not_dax_capable, &blocksize);
>  
>  out:
>  	dm_put_live_table(md, srcu_idx);
> diff --git a/drivers/md/dm.h b/drivers/md/dm.h
> index fffe1e289c53..b441ad772c18 100644
> --- a/drivers/md/dm.h
> +++ b/drivers/md/dm.h
> @@ -73,7 +73,7 @@ void dm_table_free_md_mempools(struct dm_table *t);
>  struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
>  bool dm_table_supports_dax(struct dm_table *t, iterate_devices_callout_fn fn,
>  			   int *blocksize);
> -int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
> +int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
>  			   sector_t start, sector_t len, void *data);
>  
>  void dm_lock_md_type(struct mapped_device *md);
>
Jingbo Xu Feb. 4, 2021, 6:42 a.m. UTC | #2
Any comment?

Thanks,
Jeffle


On 2/2/21 11:35 AM, Jeffle Xu wrote:
> According to the definition of dm_iterate_devices_fn:
>  * This function must iterate through each section of device used by the
>  * target until it encounters a non-zero return code, which it then returns.
>  * Returns zero if no callout returned non-zero.
> 
> For some target type (e.g., dm-stripe), one call of iterate_devices() may
> iterate multiple underlying devices internally, in which case a non-zero
> return code returned by iterate_devices_callout_fn will stop the iteration
> in advance.
> 
> Thus if we want to ensure that _all_ underlying devices support some kind of
> attribute, the iteration structure like dm_table_supports_nowait() should be
> used, while the input iterate_devices_callout_fn should handle the 'not
> support' semantics. On the opposite, the iteration structure like
> dm_table_any_device_attribute() should be used if _any_ underlying device
> supporting this attibute is sufficient. In this case, the input
> iterate_devices_callout_fn should handle the 'support' semantics.
> 
> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
> ---
>  drivers/md/dm-table.c | 84 ++++++++++++++++++++++---------------------
>  drivers/md/dm.c       |  2 +-
>  drivers/md/dm.h       |  2 +-
>  3 files changed, 46 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
> index 4acf2342f7ad..53dcbf75eda9 100644
> --- a/drivers/md/dm-table.c
> +++ b/drivers/md/dm-table.c
> @@ -820,24 +820,24 @@ void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type)
>  EXPORT_SYMBOL_GPL(dm_table_set_type);
>  
>  /* validate the dax capability of the target device span */
> -int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
> +int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
>  			sector_t start, sector_t len, void *data)
>  {
>  	int blocksize = *(int *) data, id;
>  	bool rc;
>  
>  	id = dax_read_lock();
> -	rc = dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
> +	rc = !dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
>  	dax_read_unlock(id);
>  
>  	return rc;
>  }
>  
>  /* Check devices support synchronous DAX */
> -static int device_dax_synchronous(struct dm_target *ti, struct dm_dev *dev,
> +static int device_not_dax_synchronous_capable(struct dm_target *ti, struct dm_dev *dev,
>  				  sector_t start, sector_t len, void *data)
>  {
> -	return dev->dax_dev && dax_synchronous(dev->dax_dev);
> +	return !dev->dax_dev || !dax_synchronous(dev->dax_dev);
>  }
>  
>  bool dm_table_supports_dax(struct dm_table *t,
> @@ -854,7 +854,7 @@ bool dm_table_supports_dax(struct dm_table *t,
>  			return false;
>  
>  		if (!ti->type->iterate_devices ||
> -		    !ti->type->iterate_devices(ti, iterate_fn, blocksize))
> +		    ti->type->iterate_devices(ti, iterate_fn, blocksize))
>  			return false;
>  	}
>  
> @@ -925,7 +925,7 @@ static int dm_table_determine_type(struct dm_table *t)
>  verify_bio_based:
>  		/* We must use this table as bio-based */
>  		t->type = DM_TYPE_BIO_BASED;
> -		if (dm_table_supports_dax(t, device_supports_dax, &page_size) ||
> +		if (dm_table_supports_dax(t, device_not_dax_capable, &page_size) ||
>  		    (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) {
>  			t->type = DM_TYPE_DAX_BIO_BASED;
>  		}
> @@ -1595,12 +1595,12 @@ static int dm_table_supports_dax_write_cache(struct dm_table *t)
>  	return false;
>  }
>  
> -static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev,
> +static int device_is_rot(struct dm_target *ti, struct dm_dev *dev,
>  			    sector_t start, sector_t len, void *data)
>  {
>  	struct request_queue *q = bdev_get_queue(dev->bdev);
>  
> -	return q && blk_queue_nonrot(q);
> +	return q && !blk_queue_nonrot(q);
>  }
>  
>  static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
> @@ -1611,8 +1611,8 @@ static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
>  	return q && !blk_queue_add_random(q);
>  }
>  
> -static bool dm_table_all_devices_attribute(struct dm_table *t,
> -					   iterate_devices_callout_fn func)
> +static bool dm_table_any_device_attribute(struct dm_table *t,
> +					  iterate_devices_callout_fn func)
>  {
>  	struct dm_target *ti;
>  	unsigned i;
> @@ -1620,12 +1620,12 @@ static bool dm_table_all_devices_attribute(struct dm_table *t,
>  	for (i = 0; i < dm_table_get_num_targets(t); i++) {
>  		ti = dm_table_get_target(t, i);
>  
> -		if (!ti->type->iterate_devices ||
> -		    !ti->type->iterate_devices(ti, func, NULL))
> -			return false;
> +		if (ti->type->iterate_devices &&
> +		    ti->type->iterate_devices(ti, func, NULL))
> +			return true;
>  	}
>  
> -	return true;
> +	return false;
>  }
>  
>  static int device_not_write_same_capable(struct dm_target *ti, struct dm_dev *dev,
> @@ -1780,26 +1780,25 @@ static int device_requires_stable_pages(struct dm_target *ti,
>  }
>  
>  /*
> - * If any underlying device requires stable pages, a table must require
> - * them as well.  Only targets that support iterate_devices are considered:
> - * don't want error, zero, etc to require stable pages.
> + * type->iterate_devices() should be called when the sanity check needs to
> + * iterate and check all underlying data devices. iterate_devices() will
> + * iterate all underlying data devices until it encounters a non-zero return
> + * code, returned by whether the input iterate_devices_callout_fn, or
> + * iterate_devices() itself internally.
> + *
> + * For some target type (e.g., dm-stripe), one call of iterate_devices() may
> + * iterate multiple underlying devices internally, in which case a non-zero
> + * return code returned by iterate_devices_callout_fn will stop the iteration
> + * in advance.
> + *
> + * Thus if we want to ensure that _all_ underlying devices support some kind of
> + * attribute, the iteration structure like dm_table_supports_nowait() should be
> + * used, while the input iterate_devices_callout_fn should handle the 'not
> + * support' semantics. On the opposite, the iteration structure like
> + * dm_table_any_device_attribute() should be used if _any_ underlying device
> + * supporting this attibute is sufficient. In this case, the input
> + * iterate_devices_callout_fn should handle the 'support' semantics.
>   */
> -static bool dm_table_requires_stable_pages(struct dm_table *t)
> -{
> -	struct dm_target *ti;
> -	unsigned i;
> -
> -	for (i = 0; i < dm_table_get_num_targets(t); i++) {
> -		ti = dm_table_get_target(t, i);
> -
> -		if (ti->type->iterate_devices &&
> -		    ti->type->iterate_devices(ti, device_requires_stable_pages, NULL))
> -			return true;
> -	}
> -
> -	return false;
> -}
> -
>  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  			       struct queue_limits *limits)
>  {
> @@ -1837,9 +1836,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  	}
>  	blk_queue_write_cache(q, wc, fua);
>  
> -	if (dm_table_supports_dax(t, device_supports_dax, &page_size)) {
> +	if (dm_table_supports_dax(t, device_not_dax_capable, &page_size)) {
>  		blk_queue_flag_set(QUEUE_FLAG_DAX, q);
> -		if (dm_table_supports_dax(t, device_dax_synchronous, NULL))
> +		if (dm_table_supports_dax(t, device_not_dax_synchronous_capable, NULL))
>  			set_dax_synchronous(t->md->dax_dev);
>  	}
>  	else
> @@ -1849,10 +1848,10 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  		dax_write_cache(t->md->dax_dev, true);
>  
>  	/* Ensure that all underlying devices are non-rotational. */
> -	if (dm_table_all_devices_attribute(t, device_is_nonrot))
> -		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
> -	else
> +	if (dm_table_any_device_attribute(t, device_is_rot))
>  		blk_queue_flag_clear(QUEUE_FLAG_NONROT, q);
> +	else
> +		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
>  
>  	if (!dm_table_supports_write_same(t))
>  		q->limits.max_write_same_sectors = 0;
> @@ -1864,8 +1863,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  	/*
>  	 * Some devices don't use blk_integrity but still want stable pages
>  	 * because they do their own checksumming.
> +	 * If any underlying device requires stable pages, a table must require
> +	 * them as well.  Only targets that support iterate_devices are considered:
> +	 * don't want error, zero, etc to require stable pages.
>  	 */
> -	if (dm_table_requires_stable_pages(t))
> +	if (dm_table_any_device_attribute(t, device_requires_stable_pages))
>  		blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, q);
>  	else
>  		blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, q);
> @@ -1876,8 +1878,10 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
>  	 * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not
>  	 * have it set.
>  	 */
> -	if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
> +	if (dm_table_any_device_attribute(t, device_is_not_random))
>  		blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
> +	else
> +		blk_queue_flag_set(QUEUE_FLAG_ADD_RANDOM, q);
>  
>  	/*
>  	 * For a zoned target, the number of zones should be updated for the
> diff --git a/drivers/md/dm.c b/drivers/md/dm.c
> index 7bac564f3faa..8a3d73efb9dd 100644
> --- a/drivers/md/dm.c
> +++ b/drivers/md/dm.c
> @@ -1128,7 +1128,7 @@ static bool dm_dax_supported(struct dax_device *dax_dev, struct block_device *bd
>  	if (!map)
>  		goto out;
>  
> -	ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
> +	ret = dm_table_supports_dax(map, device_not_dax_capable, &blocksize);
>  
>  out:
>  	dm_put_live_table(md, srcu_idx);
> diff --git a/drivers/md/dm.h b/drivers/md/dm.h
> index fffe1e289c53..b441ad772c18 100644
> --- a/drivers/md/dm.h
> +++ b/drivers/md/dm.h
> @@ -73,7 +73,7 @@ void dm_table_free_md_mempools(struct dm_table *t);
>  struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
>  bool dm_table_supports_dax(struct dm_table *t, iterate_devices_callout_fn fn,
>  			   int *blocksize);
> -int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
> +int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
>  			   sector_t start, sector_t len, void *data);
>  
>  void dm_lock_md_type(struct mapped_device *md);
>
Mike Snitzer Feb. 5, 2021, 6:39 p.m. UTC | #3
On Mon, Feb 01 2021 at 10:35pm -0500,
Jeffle Xu <jefflexu@linux.alibaba.com> wrote:

> According to the definition of dm_iterate_devices_fn:
>  * This function must iterate through each section of device used by the
>  * target until it encounters a non-zero return code, which it then returns.
>  * Returns zero if no callout returned non-zero.
> 
> For some target type (e.g., dm-stripe), one call of iterate_devices() may
> iterate multiple underlying devices internally, in which case a non-zero
> return code returned by iterate_devices_callout_fn will stop the iteration
> in advance.
> 
> Thus if we want to ensure that _all_ underlying devices support some kind of
> attribute, the iteration structure like dm_table_supports_nowait() should be
> used, while the input iterate_devices_callout_fn should handle the 'not
> support' semantics. On the opposite, the iteration structure like
> dm_table_any_device_attribute() should be used if _any_ underlying device
> supporting this attibute is sufficient. In this case, the input
> iterate_devices_callout_fn should handle the 'support' semantics.
> 
> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>

Thanks for auditing and fixing this up.  It has been on my todo so
you've really helped me out -- your changes look correct to me.

I've staged it for 5.12, the stable fix will likely need manual fixups
depending on the stable tree... we'll just need to assist with
backport(s) as needed.

Thanks again,
Mike

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
Jingbo Xu Feb. 6, 2021, 1:38 a.m. UTC | #4
On 2/6/21 2:39 AM, Mike Snitzer wrote:
> On Mon, Feb 01 2021 at 10:35pm -0500,
> Jeffle Xu <jefflexu@linux.alibaba.com> wrote:
> 
>> According to the definition of dm_iterate_devices_fn:
>>  * This function must iterate through each section of device used by the
>>  * target until it encounters a non-zero return code, which it then returns.
>>  * Returns zero if no callout returned non-zero.
>>
>> For some target type (e.g., dm-stripe), one call of iterate_devices() may
>> iterate multiple underlying devices internally, in which case a non-zero
>> return code returned by iterate_devices_callout_fn will stop the iteration
>> in advance.
>>
>> Thus if we want to ensure that _all_ underlying devices support some kind of
>> attribute, the iteration structure like dm_table_supports_nowait() should be
>> used, while the input iterate_devices_callout_fn should handle the 'not
>> support' semantics. On the opposite, the iteration structure like
>> dm_table_any_device_attribute() should be used if _any_ underlying device
>> supporting this attibute is sufficient. In this case, the input
>> iterate_devices_callout_fn should handle the 'support' semantics.
>>
>> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
>> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
>> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
> 
> Thanks for auditing and fixing this up.  It has been on my todo so
> you've really helped me out -- your changes look correct to me.
> 
> I've staged it for 5.12, the stable fix will likely need manual fixups
> depending on the stable tree... we'll just need to assist with
> backport(s) as needed.
> 

Thanks.

Actually, I have one v2 version patch, fixing more issues, and some
explanation comment included. Maybe I should send the v2?
Jingbo Xu Feb. 6, 2021, 2:03 a.m. UTC | #5
On 2/6/21 2:39 AM, Mike Snitzer wrote:
> On Mon, Feb 01 2021 at 10:35pm -0500,
> Jeffle Xu <jefflexu@linux.alibaba.com> wrote:
> 
>> According to the definition of dm_iterate_devices_fn:
>>  * This function must iterate through each section of device used by the
>>  * target until it encounters a non-zero return code, which it then returns.
>>  * Returns zero if no callout returned non-zero.
>>
>> For some target type (e.g., dm-stripe), one call of iterate_devices() may
>> iterate multiple underlying devices internally, in which case a non-zero
>> return code returned by iterate_devices_callout_fn will stop the iteration
>> in advance.
>>
>> Thus if we want to ensure that _all_ underlying devices support some kind of
>> attribute, the iteration structure like dm_table_supports_nowait() should be
>> used, while the input iterate_devices_callout_fn should handle the 'not
>> support' semantics. On the opposite, the iteration structure like
>> dm_table_any_device_attribute() should be used if _any_ underlying device
>> supporting this attibute is sufficient. In this case, the input
>> iterate_devices_callout_fn should handle the 'support' semantics.
>>
>> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
>> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
>> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
> 
> Thanks for auditing and fixing this up.  It has been on my todo so
> you've really helped me out -- your changes look correct to me.
> 
> I've staged it for 5.12, the stable fix will likely need manual fixups
> depending on the stable tree... we'll just need to assist with
> backport(s) as needed.

I'm glad to help offer the stable backport. But I don't know which
kernel version the stable kernel is still being maintained. Also which
mailing list I should send to when I finished backporting?
Mike Snitzer Feb. 8, 2021, 3:17 p.m. UTC | #6
On Fri, Feb 05 2021 at  9:03pm -0500,
JeffleXu <jefflexu@linux.alibaba.com> wrote:

> 
> 
> On 2/6/21 2:39 AM, Mike Snitzer wrote:
> > On Mon, Feb 01 2021 at 10:35pm -0500,
> > Jeffle Xu <jefflexu@linux.alibaba.com> wrote:
> > 
> >> According to the definition of dm_iterate_devices_fn:
> >>  * This function must iterate through each section of device used by the
> >>  * target until it encounters a non-zero return code, which it then returns.
> >>  * Returns zero if no callout returned non-zero.
> >>
> >> For some target type (e.g., dm-stripe), one call of iterate_devices() may
> >> iterate multiple underlying devices internally, in which case a non-zero
> >> return code returned by iterate_devices_callout_fn will stop the iteration
> >> in advance.
> >>
> >> Thus if we want to ensure that _all_ underlying devices support some kind of
> >> attribute, the iteration structure like dm_table_supports_nowait() should be
> >> used, while the input iterate_devices_callout_fn should handle the 'not
> >> support' semantics. On the opposite, the iteration structure like
> >> dm_table_any_device_attribute() should be used if _any_ underlying device
> >> supporting this attibute is sufficient. In this case, the input
> >> iterate_devices_callout_fn should handle the 'support' semantics.
> >>
> >> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
> >> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
> >> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
> >> Cc: stable@vger.kernel.org
> >> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
> > 
> > Thanks for auditing and fixing this up.  It has been on my todo so
> > you've really helped me out -- your changes look correct to me.
> > 
> > I've staged it for 5.12, the stable fix will likely need manual fixups
> > depending on the stable tree... we'll just need to assist with
> > backport(s) as needed.
> 
> I'm glad to help offer the stable backport. But I don't know which
> kernel version the stable kernel is still being maintained. Also which
> mailing list I should send to when I finished backporting?

All your v2 changes speak to needing more discipline in crafting
individual stable@ fixes that are applicable to various kernels.. when
all applied to mainline then it'd be the equivalent of your single
monolithic patch.

But without splitting the changes into separate patches, for stable@'s
benefit, we'll have a much more difficult time of shepherding the
applicable changes into the disparate stable@ kernels.

I'll have a look at splitting your v2 up accordingly.

Mike

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
Mike Snitzer Feb. 9, 2021, 5:29 a.m. UTC | #7
On Mon, Feb 08 2021 at 10:17am -0500,
Mike Snitzer <snitzer@redhat.com> wrote:

> On Fri, Feb 05 2021 at  9:03pm -0500,
> JeffleXu <jefflexu@linux.alibaba.com> wrote:
> 
> > 
> > 
> > On 2/6/21 2:39 AM, Mike Snitzer wrote:
> > > On Mon, Feb 01 2021 at 10:35pm -0500,
> > > Jeffle Xu <jefflexu@linux.alibaba.com> wrote:
> > > 
> > >> According to the definition of dm_iterate_devices_fn:
> > >>  * This function must iterate through each section of device used by the
> > >>  * target until it encounters a non-zero return code, which it then returns.
> > >>  * Returns zero if no callout returned non-zero.
> > >>
> > >> For some target type (e.g., dm-stripe), one call of iterate_devices() may
> > >> iterate multiple underlying devices internally, in which case a non-zero
> > >> return code returned by iterate_devices_callout_fn will stop the iteration
> > >> in advance.
> > >>
> > >> Thus if we want to ensure that _all_ underlying devices support some kind of
> > >> attribute, the iteration structure like dm_table_supports_nowait() should be
> > >> used, while the input iterate_devices_callout_fn should handle the 'not
> > >> support' semantics. On the opposite, the iteration structure like
> > >> dm_table_any_device_attribute() should be used if _any_ underlying device
> > >> supporting this attibute is sufficient. In this case, the input
> > >> iterate_devices_callout_fn should handle the 'support' semantics.
> > >>
> > >> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
> > >> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
> > >> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
> > >> Cc: stable@vger.kernel.org
> > >> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
> > > 
> > > Thanks for auditing and fixing this up.  It has been on my todo so
> > > you've really helped me out -- your changes look correct to me.
> > > 
> > > I've staged it for 5.12, the stable fix will likely need manual fixups
> > > depending on the stable tree... we'll just need to assist with
> > > backport(s) as needed.
> > 
> > I'm glad to help offer the stable backport. But I don't know which
> > kernel version the stable kernel is still being maintained. Also which
> > mailing list I should send to when I finished backporting?
> 
> All your v2 changes speak to needing more discipline in crafting
> individual stable@ fixes that are applicable to various kernels.. when
> all applied to mainline then it'd be the equivalent of your single
> monolithic patch.
> 
> But without splitting the changes into separate patches, for stable@'s
> benefit, we'll have a much more difficult time of shepherding the
> applicable changes into the disparate stable@ kernels.
> 
> I'll have a look at splitting your v2 up accordingly.

Hi, please see these commits that I've staged in linux-next via:
https://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git/log/?h=for-next

1141b9133777 dm table: fix iterate_devices based device capability checks
0224c5e6fd07 dm table: fix DAX iterate_devices based device capability checks
76b0e14be03f dm table: fix zoned iterate_devices based device capability checks
55cdd7435e97 dm table: remove needless request_queue NULL pointer checks

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
Jingbo Xu Feb. 9, 2021, 7:06 a.m. UTC | #8
On 2/9/21 1:29 PM, Mike Snitzer wrote:
> On Mon, Feb 08 2021 at 10:17am -0500,
> Mike Snitzer <snitzer@redhat.com> wrote:
> 
>> On Fri, Feb 05 2021 at  9:03pm -0500,
>> JeffleXu <jefflexu@linux.alibaba.com> wrote:
>>
>>>
>>>
>>> On 2/6/21 2:39 AM, Mike Snitzer wrote:
>>>> On Mon, Feb 01 2021 at 10:35pm -0500,
>>>> Jeffle Xu <jefflexu@linux.alibaba.com> wrote:
>>>>
>>>>> According to the definition of dm_iterate_devices_fn:
>>>>>  * This function must iterate through each section of device used by the
>>>>>  * target until it encounters a non-zero return code, which it then returns.
>>>>>  * Returns zero if no callout returned non-zero.
>>>>>
>>>>> For some target type (e.g., dm-stripe), one call of iterate_devices() may
>>>>> iterate multiple underlying devices internally, in which case a non-zero
>>>>> return code returned by iterate_devices_callout_fn will stop the iteration
>>>>> in advance.
>>>>>
>>>>> Thus if we want to ensure that _all_ underlying devices support some kind of
>>>>> attribute, the iteration structure like dm_table_supports_nowait() should be
>>>>> used, while the input iterate_devices_callout_fn should handle the 'not
>>>>> support' semantics. On the opposite, the iteration structure like
>>>>> dm_table_any_device_attribute() should be used if _any_ underlying device
>>>>> supporting this attibute is sufficient. In this case, the input
>>>>> iterate_devices_callout_fn should handle the 'support' semantics.
>>>>>
>>>>> Fixes: 545ed20e6df6 ("dm: add infrastructure for DAX support")
>>>>> Fixes: c3c4555edd10 ("dm table: clear add_random unless all devices have it set")
>>>>> Fixes: 4693c9668fdc ("dm table: propagate non rotational flag")
>>>>> Cc: stable@vger.kernel.org
>>>>> Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
>>>>
>>>> Thanks for auditing and fixing this up.  It has been on my todo so
>>>> you've really helped me out -- your changes look correct to me.
>>>>
>>>> I've staged it for 5.12, the stable fix will likely need manual fixups
>>>> depending on the stable tree... we'll just need to assist with
>>>> backport(s) as needed.
>>>
>>> I'm glad to help offer the stable backport. But I don't know which
>>> kernel version the stable kernel is still being maintained. Also which
>>> mailing list I should send to when I finished backporting?
>>
>> All your v2 changes speak to needing more discipline in crafting
>> individual stable@ fixes that are applicable to various kernels.. when
>> all applied to mainline then it'd be the equivalent of your single
>> monolithic patch.
>>
>> But without splitting the changes into separate patches, for stable@'s
>> benefit, we'll have a much more difficult time of shepherding the
>> applicable changes into the disparate stable@ kernels.
>>
>> I'll have a look at splitting your v2 up accordingly.
> 
> Hi, please see these commits that I've staged in linux-next via:
> https://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git/log/?h=for-next
> 
> 1141b9133777 dm table: fix iterate_devices based device capability checks
> 0224c5e6fd07 dm table: fix DAX iterate_devices based device capability checks
> 76b0e14be03f dm table: fix zoned iterate_devices based device capability checks
> 55cdd7435e97 dm table: remove needless request_queue NULL pointer checks
> 

Thanks. This series looks good to me.

I suddenly find that the semantics of patch 1 (1141b9133777 dm table:
fix iterate_devices based device capability checks) is a little
different with the original context.

-	if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t,
device_is_not_random))
+	if (dm_table_any_dev_attr(t, device_is_not_random))
 		blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
+	else
+		blk_queue_flag_set(QUEUE_FLAG_ADD_RANDOM, q);

In the original context, QUEUE_FLAG_ADD_RANDOM will only be cleared, it
won't be set, while it could be set after patch 1. But I could see no
harm of setting QUEUE_FLAG_ADD_RANDOM flag though.

FYI. Currently only scsi devices are still using QUEUE_FLAG_ADD_RANDOM
flag, as all non-rotational devices should not set this flag since
commit b277da0a8a59 ("block: disable entropy contributions for nonrot
devices").
Mike Snitzer Feb. 9, 2021, 1:51 p.m. UTC | #9
On Tue, Feb 09 2021 at  2:06am -0500,
JeffleXu <jefflexu@linux.alibaba.com> wrote:

> 
> 
> On 2/9/21 1:29 PM, Mike Snitzer wrote:
> > 
> > Hi, please see these commits that I've staged in linux-next via:
> > https://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git/log/?h=for-next
> > 
> > 1141b9133777 dm table: fix iterate_devices based device capability checks
> > 0224c5e6fd07 dm table: fix DAX iterate_devices based device capability checks
> > 76b0e14be03f dm table: fix zoned iterate_devices based device capability checks
> > 55cdd7435e97 dm table: remove needless request_queue NULL pointer checks
> > 
> 
> Thanks. This series looks good to me.
> 
> I suddenly find that the semantics of patch 1 (1141b9133777 dm table:
> fix iterate_devices based device capability checks) is a little
> different with the original context.
> 
> -	if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t,
> device_is_not_random))
> +	if (dm_table_any_dev_attr(t, device_is_not_random))
>  		blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
> +	else
> +		blk_queue_flag_set(QUEUE_FLAG_ADD_RANDOM, q);
> 
> In the original context, QUEUE_FLAG_ADD_RANDOM will only be cleared, it
> won't be set, while it could be set after patch 1. But I could see no
> harm of setting QUEUE_FLAG_ADD_RANDOM flag though.
> 
> FYI. Currently only scsi devices are still using QUEUE_FLAG_ADD_RANDOM
> flag, as all non-rotational devices should not set this flag since
> commit b277da0a8a59 ("block: disable entropy contributions for nonrot
> devices").

I fixed it, thanks.

Mike

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
diff mbox series

Patch

diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 4acf2342f7ad..53dcbf75eda9 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -820,24 +820,24 @@  void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type)
 EXPORT_SYMBOL_GPL(dm_table_set_type);
 
 /* validate the dax capability of the target device span */
-int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
 			sector_t start, sector_t len, void *data)
 {
 	int blocksize = *(int *) data, id;
 	bool rc;
 
 	id = dax_read_lock();
-	rc = dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
+	rc = !dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
 	dax_read_unlock(id);
 
 	return rc;
 }
 
 /* Check devices support synchronous DAX */
-static int device_dax_synchronous(struct dm_target *ti, struct dm_dev *dev,
+static int device_not_dax_synchronous_capable(struct dm_target *ti, struct dm_dev *dev,
 				  sector_t start, sector_t len, void *data)
 {
-	return dev->dax_dev && dax_synchronous(dev->dax_dev);
+	return !dev->dax_dev || !dax_synchronous(dev->dax_dev);
 }
 
 bool dm_table_supports_dax(struct dm_table *t,
@@ -854,7 +854,7 @@  bool dm_table_supports_dax(struct dm_table *t,
 			return false;
 
 		if (!ti->type->iterate_devices ||
-		    !ti->type->iterate_devices(ti, iterate_fn, blocksize))
+		    ti->type->iterate_devices(ti, iterate_fn, blocksize))
 			return false;
 	}
 
@@ -925,7 +925,7 @@  static int dm_table_determine_type(struct dm_table *t)
 verify_bio_based:
 		/* We must use this table as bio-based */
 		t->type = DM_TYPE_BIO_BASED;
-		if (dm_table_supports_dax(t, device_supports_dax, &page_size) ||
+		if (dm_table_supports_dax(t, device_not_dax_capable, &page_size) ||
 		    (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) {
 			t->type = DM_TYPE_DAX_BIO_BASED;
 		}
@@ -1595,12 +1595,12 @@  static int dm_table_supports_dax_write_cache(struct dm_table *t)
 	return false;
 }
 
-static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev,
+static int device_is_rot(struct dm_target *ti, struct dm_dev *dev,
 			    sector_t start, sector_t len, void *data)
 {
 	struct request_queue *q = bdev_get_queue(dev->bdev);
 
-	return q && blk_queue_nonrot(q);
+	return q && !blk_queue_nonrot(q);
 }
 
 static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
@@ -1611,8 +1611,8 @@  static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev,
 	return q && !blk_queue_add_random(q);
 }
 
-static bool dm_table_all_devices_attribute(struct dm_table *t,
-					   iterate_devices_callout_fn func)
+static bool dm_table_any_device_attribute(struct dm_table *t,
+					  iterate_devices_callout_fn func)
 {
 	struct dm_target *ti;
 	unsigned i;
@@ -1620,12 +1620,12 @@  static bool dm_table_all_devices_attribute(struct dm_table *t,
 	for (i = 0; i < dm_table_get_num_targets(t); i++) {
 		ti = dm_table_get_target(t, i);
 
-		if (!ti->type->iterate_devices ||
-		    !ti->type->iterate_devices(ti, func, NULL))
-			return false;
+		if (ti->type->iterate_devices &&
+		    ti->type->iterate_devices(ti, func, NULL))
+			return true;
 	}
 
-	return true;
+	return false;
 }
 
 static int device_not_write_same_capable(struct dm_target *ti, struct dm_dev *dev,
@@ -1780,26 +1780,25 @@  static int device_requires_stable_pages(struct dm_target *ti,
 }
 
 /*
- * If any underlying device requires stable pages, a table must require
- * them as well.  Only targets that support iterate_devices are considered:
- * don't want error, zero, etc to require stable pages.
+ * type->iterate_devices() should be called when the sanity check needs to
+ * iterate and check all underlying data devices. iterate_devices() will
+ * iterate all underlying data devices until it encounters a non-zero return
+ * code, returned by whether the input iterate_devices_callout_fn, or
+ * iterate_devices() itself internally.
+ *
+ * For some target type (e.g., dm-stripe), one call of iterate_devices() may
+ * iterate multiple underlying devices internally, in which case a non-zero
+ * return code returned by iterate_devices_callout_fn will stop the iteration
+ * in advance.
+ *
+ * Thus if we want to ensure that _all_ underlying devices support some kind of
+ * attribute, the iteration structure like dm_table_supports_nowait() should be
+ * used, while the input iterate_devices_callout_fn should handle the 'not
+ * support' semantics. On the opposite, the iteration structure like
+ * dm_table_any_device_attribute() should be used if _any_ underlying device
+ * supporting this attibute is sufficient. In this case, the input
+ * iterate_devices_callout_fn should handle the 'support' semantics.
  */
-static bool dm_table_requires_stable_pages(struct dm_table *t)
-{
-	struct dm_target *ti;
-	unsigned i;
-
-	for (i = 0; i < dm_table_get_num_targets(t); i++) {
-		ti = dm_table_get_target(t, i);
-
-		if (ti->type->iterate_devices &&
-		    ti->type->iterate_devices(ti, device_requires_stable_pages, NULL))
-			return true;
-	}
-
-	return false;
-}
-
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
 			       struct queue_limits *limits)
 {
@@ -1837,9 +1836,9 @@  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
 	}
 	blk_queue_write_cache(q, wc, fua);
 
-	if (dm_table_supports_dax(t, device_supports_dax, &page_size)) {
+	if (dm_table_supports_dax(t, device_not_dax_capable, &page_size)) {
 		blk_queue_flag_set(QUEUE_FLAG_DAX, q);
-		if (dm_table_supports_dax(t, device_dax_synchronous, NULL))
+		if (dm_table_supports_dax(t, device_not_dax_synchronous_capable, NULL))
 			set_dax_synchronous(t->md->dax_dev);
 	}
 	else
@@ -1849,10 +1848,10 @@  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
 		dax_write_cache(t->md->dax_dev, true);
 
 	/* Ensure that all underlying devices are non-rotational. */
-	if (dm_table_all_devices_attribute(t, device_is_nonrot))
-		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-	else
+	if (dm_table_any_device_attribute(t, device_is_rot))
 		blk_queue_flag_clear(QUEUE_FLAG_NONROT, q);
+	else
+		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
 
 	if (!dm_table_supports_write_same(t))
 		q->limits.max_write_same_sectors = 0;
@@ -1864,8 +1863,11 @@  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
 	/*
 	 * Some devices don't use blk_integrity but still want stable pages
 	 * because they do their own checksumming.
+	 * If any underlying device requires stable pages, a table must require
+	 * them as well.  Only targets that support iterate_devices are considered:
+	 * don't want error, zero, etc to require stable pages.
 	 */
-	if (dm_table_requires_stable_pages(t))
+	if (dm_table_any_device_attribute(t, device_requires_stable_pages))
 		blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, q);
 	else
 		blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, q);
@@ -1876,8 +1878,10 @@  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
 	 * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not
 	 * have it set.
 	 */
-	if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
+	if (dm_table_any_device_attribute(t, device_is_not_random))
 		blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
+	else
+		blk_queue_flag_set(QUEUE_FLAG_ADD_RANDOM, q);
 
 	/*
 	 * For a zoned target, the number of zones should be updated for the
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 7bac564f3faa..8a3d73efb9dd 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1128,7 +1128,7 @@  static bool dm_dax_supported(struct dax_device *dax_dev, struct block_device *bd
 	if (!map)
 		goto out;
 
-	ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
+	ret = dm_table_supports_dax(map, device_not_dax_capable, &blocksize);
 
 out:
 	dm_put_live_table(md, srcu_idx);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index fffe1e289c53..b441ad772c18 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -73,7 +73,7 @@  void dm_table_free_md_mempools(struct dm_table *t);
 struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
 bool dm_table_supports_dax(struct dm_table *t, iterate_devices_callout_fn fn,
 			   int *blocksize);
-int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
 			   sector_t start, sector_t len, void *data);
 
 void dm_lock_md_type(struct mapped_device *md);